NorFlash.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  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 "NorFlash.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. if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) {
  53. do {
  54. // Request a lock setup
  55. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
  56. // Request an unlock
  57. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
  58. // Send command for reading device id
  59. SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
  60. // Read block lock status
  61. LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));
  62. // Decode block lock status
  63. LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);
  64. } while ((LockStatus & 0x1) == 1);
  65. } else {
  66. // Request a lock setup
  67. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
  68. // Request an unlock
  69. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
  70. // Wait until the status register gives us the all clear
  71. do {
  72. LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
  73. } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  74. }
  75. // Put device back into Read Array mode
  76. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
  77. DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));
  78. return EFI_SUCCESS;
  79. }
  80. EFI_STATUS
  81. NorFlashUnlockSingleBlockIfNecessary (
  82. IN NOR_FLASH_INSTANCE *Instance,
  83. IN UINTN BlockAddress
  84. )
  85. {
  86. EFI_STATUS Status;
  87. Status = EFI_SUCCESS;
  88. if (NorFlashBlockIsLocked (Instance, BlockAddress)) {
  89. Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
  90. }
  91. return Status;
  92. }
  93. /**
  94. * The following function presumes that the block has already been unlocked.
  95. **/
  96. EFI_STATUS
  97. NorFlashEraseSingleBlock (
  98. IN NOR_FLASH_INSTANCE *Instance,
  99. IN UINTN BlockAddress
  100. )
  101. {
  102. EFI_STATUS Status;
  103. UINT32 StatusRegister;
  104. Status = EFI_SUCCESS;
  105. // Request a block erase and then confirm it
  106. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
  107. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
  108. // Wait until the status register gives us the all clear
  109. do {
  110. StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
  111. } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  112. if (StatusRegister & P30_SR_BIT_VPP) {
  113. DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
  114. Status = EFI_DEVICE_ERROR;
  115. }
  116. if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
  117. DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
  118. Status = EFI_DEVICE_ERROR;
  119. }
  120. if (StatusRegister & P30_SR_BIT_ERASE) {
  121. DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
  122. Status = EFI_DEVICE_ERROR;
  123. }
  124. if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
  125. // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
  126. DEBUG ((DEBUG_INFO, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
  127. Status = EFI_WRITE_PROTECTED;
  128. }
  129. if (EFI_ERROR (Status)) {
  130. // Clear the Status Register
  131. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
  132. }
  133. // Put device back into Read Array mode
  134. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  135. return Status;
  136. }
  137. EFI_STATUS
  138. NorFlashWriteSingleWord (
  139. IN NOR_FLASH_INSTANCE *Instance,
  140. IN UINTN WordAddress,
  141. IN UINT32 WriteData
  142. )
  143. {
  144. EFI_STATUS Status;
  145. UINT32 StatusRegister;
  146. Status = EFI_SUCCESS;
  147. // Request a write single word command
  148. SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
  149. // Store the word into NOR Flash;
  150. MmioWrite32 (WordAddress, WriteData);
  151. // Wait for the write to complete and then check for any errors; i.e. check the Status Register
  152. do {
  153. // Prepare to read the status register
  154. StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
  155. // The chip is busy while the WRITE bit is not asserted
  156. } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  157. // Perform a full status check:
  158. // Mask the relevant bits of Status Register.
  159. // Everything should be zero, if not, we have a problem
  160. if (StatusRegister & P30_SR_BIT_VPP) {
  161. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress));
  162. Status = EFI_DEVICE_ERROR;
  163. }
  164. if (StatusRegister & P30_SR_BIT_PROGRAM) {
  165. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));
  166. Status = EFI_DEVICE_ERROR;
  167. }
  168. if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
  169. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress));
  170. Status = EFI_DEVICE_ERROR;
  171. }
  172. if (!EFI_ERROR (Status)) {
  173. // Clear the Status Register
  174. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
  175. }
  176. // Put device back into Read Array mode
  177. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  178. return Status;
  179. }
  180. /*
  181. * Writes data to the NOR Flash using the Buffered Programming method.
  182. *
  183. * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
  184. * Therefore this function will only handle buffers up to 32 words or 128 bytes.
  185. * To deal with larger buffers, call this function again.
  186. *
  187. * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
  188. * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
  189. *
  190. * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
  191. * then programming time is doubled and power consumption is increased.
  192. * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
  193. * i.e. the last 4 bits of the target start address must be zero: 0x......00
  194. */
  195. EFI_STATUS
  196. NorFlashWriteBuffer (
  197. IN NOR_FLASH_INSTANCE *Instance,
  198. IN UINTN TargetAddress,
  199. IN UINTN BufferSizeInBytes,
  200. IN UINT32 *Buffer
  201. )
  202. {
  203. EFI_STATUS Status;
  204. UINTN BufferSizeInWords;
  205. UINTN Count;
  206. volatile UINT32 *Data;
  207. UINTN WaitForBuffer;
  208. BOOLEAN BufferAvailable;
  209. UINT32 StatusRegister;
  210. WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
  211. BufferAvailable = FALSE;
  212. // Check that the target address does not cross a 32-word boundary.
  213. if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
  214. return EFI_INVALID_PARAMETER;
  215. }
  216. // Check there are some data to program
  217. if (BufferSizeInBytes == 0) {
  218. return EFI_BUFFER_TOO_SMALL;
  219. }
  220. // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
  221. if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
  222. return EFI_BAD_BUFFER_SIZE;
  223. }
  224. // Check that the buffer size is a multiple of 32-bit words
  225. if ((BufferSizeInBytes % 4) != 0) {
  226. return EFI_BAD_BUFFER_SIZE;
  227. }
  228. // Pre-programming conditions checked, now start the algorithm.
  229. // Prepare the data destination address
  230. Data = (UINT32 *)TargetAddress;
  231. // Check the availability of the buffer
  232. do {
  233. // Issue the Buffered Program Setup command
  234. SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
  235. // Read back the status register bit#7 from the same address
  236. if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
  237. BufferAvailable = TRUE;
  238. }
  239. // Update the loop counter
  240. WaitForBuffer--;
  241. } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
  242. // The buffer was not available for writing
  243. if (WaitForBuffer == 0) {
  244. Status = EFI_DEVICE_ERROR;
  245. goto EXIT;
  246. }
  247. // From now on we work in 32-bit words
  248. BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
  249. // Write the word count, which is (buffer_size_in_words - 1),
  250. // because word count 0 means one word.
  251. SEND_NOR_COMMAND (TargetAddress, 0, (BufferSizeInWords - 1));
  252. // Write the data to the NOR Flash, advancing each address by 4 bytes
  253. for (Count = 0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
  254. MmioWrite32 ((UINTN)Data, *Buffer);
  255. }
  256. // Issue the Buffered Program Confirm command, to start the programming operation
  257. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
  258. // Wait for the write to complete and then check for any errors; i.e. check the Status Register
  259. do {
  260. StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
  261. // The chip is busy while the WRITE bit is not asserted
  262. } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  263. // Perform a full status check:
  264. // Mask the relevant bits of Status Register.
  265. // Everything should be zero, if not, we have a problem
  266. Status = EFI_SUCCESS;
  267. if (StatusRegister & P30_SR_BIT_VPP) {
  268. DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
  269. Status = EFI_DEVICE_ERROR;
  270. }
  271. if (StatusRegister & P30_SR_BIT_PROGRAM) {
  272. DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
  273. Status = EFI_DEVICE_ERROR;
  274. }
  275. if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
  276. DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress));
  277. Status = EFI_DEVICE_ERROR;
  278. }
  279. if (!EFI_ERROR (Status)) {
  280. // Clear the Status Register
  281. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
  282. }
  283. EXIT:
  284. // Put device back into Read Array mode
  285. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  286. return Status;
  287. }
  288. EFI_STATUS
  289. NorFlashWriteBlocks (
  290. IN NOR_FLASH_INSTANCE *Instance,
  291. IN EFI_LBA Lba,
  292. IN UINTN BufferSizeInBytes,
  293. IN VOID *Buffer
  294. )
  295. {
  296. UINT32 *pWriteBuffer;
  297. EFI_STATUS Status;
  298. EFI_LBA CurrentBlock;
  299. UINT32 BlockSizeInWords;
  300. UINT32 NumBlocks;
  301. UINT32 BlockCount;
  302. Status = EFI_SUCCESS;
  303. // The buffer must be valid
  304. if (Buffer == NULL) {
  305. return EFI_INVALID_PARAMETER;
  306. }
  307. if (Instance->Media.ReadOnly == TRUE) {
  308. return EFI_WRITE_PROTECTED;
  309. }
  310. // We must have some bytes to read
  311. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
  312. if (BufferSizeInBytes == 0) {
  313. return EFI_BAD_BUFFER_SIZE;
  314. }
  315. // The size of the buffer must be a multiple of the block size
  316. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize));
  317. if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
  318. return EFI_BAD_BUFFER_SIZE;
  319. }
  320. // All blocks must be within the device
  321. NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize;
  322. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));
  323. if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
  324. DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
  325. return EFI_INVALID_PARAMETER;
  326. }
  327. BlockSizeInWords = Instance->Media.BlockSize / 4;
  328. // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
  329. // to a proper data type, so use *ReadBuffer
  330. pWriteBuffer = (UINT32 *)Buffer;
  331. CurrentBlock = Lba;
  332. for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
  333. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
  334. Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
  335. if (EFI_ERROR (Status)) {
  336. break;
  337. }
  338. }
  339. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
  340. return Status;
  341. }
  342. #define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
  343. /**
  344. Copy Length bytes from Source to Destination, using aligned accesses only.
  345. Note that this implementation uses memcpy() semantics rather then memmove()
  346. semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
  347. @param DestinationBuffer The target of the copy request.
  348. @param SourceBuffer The place to copy from.
  349. @param Length The number of bytes to copy.
  350. @return Destination
  351. **/
  352. STATIC
  353. VOID *
  354. AlignedCopyMem (
  355. OUT VOID *DestinationBuffer,
  356. IN CONST VOID *SourceBuffer,
  357. IN UINTN Length
  358. )
  359. {
  360. UINT8 *Destination8;
  361. CONST UINT8 *Source8;
  362. UINT32 *Destination32;
  363. CONST UINT32 *Source32;
  364. UINT64 *Destination64;
  365. CONST UINT64 *Source64;
  366. if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 8) && (Length >= 8)) {
  367. Destination64 = DestinationBuffer;
  368. Source64 = SourceBuffer;
  369. while (Length >= 8) {
  370. *Destination64++ = *Source64++;
  371. Length -= 8;
  372. }
  373. Destination8 = (UINT8 *)Destination64;
  374. Source8 = (CONST UINT8 *)Source64;
  375. } else if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 4) && (Length >= 4)) {
  376. Destination32 = DestinationBuffer;
  377. Source32 = SourceBuffer;
  378. while (Length >= 4) {
  379. *Destination32++ = *Source32++;
  380. Length -= 4;
  381. }
  382. Destination8 = (UINT8 *)Destination32;
  383. Source8 = (CONST UINT8 *)Source32;
  384. } else {
  385. Destination8 = DestinationBuffer;
  386. Source8 = SourceBuffer;
  387. }
  388. while (Length-- != 0) {
  389. *Destination8++ = *Source8++;
  390. }
  391. return DestinationBuffer;
  392. }
  393. EFI_STATUS
  394. NorFlashReadBlocks (
  395. IN NOR_FLASH_INSTANCE *Instance,
  396. IN EFI_LBA Lba,
  397. IN UINTN BufferSizeInBytes,
  398. OUT VOID *Buffer
  399. )
  400. {
  401. UINT32 NumBlocks;
  402. UINTN StartAddress;
  403. DEBUG ((
  404. DEBUG_BLKIO,
  405. "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
  406. BufferSizeInBytes,
  407. Instance->Media.BlockSize,
  408. Instance->Media.LastBlock,
  409. Lba
  410. ));
  411. // The buffer must be valid
  412. if (Buffer == NULL) {
  413. return EFI_INVALID_PARAMETER;
  414. }
  415. // Return if we have not any byte to read
  416. if (BufferSizeInBytes == 0) {
  417. return EFI_SUCCESS;
  418. }
  419. // The size of the buffer must be a multiple of the block size
  420. if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
  421. return EFI_BAD_BUFFER_SIZE;
  422. }
  423. // All blocks must be within the device
  424. NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize;
  425. if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
  426. DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
  427. return EFI_INVALID_PARAMETER;
  428. }
  429. // Get the address to start reading from
  430. StartAddress = GET_NOR_BLOCK_ADDRESS (
  431. Instance->RegionBaseAddress,
  432. Lba,
  433. Instance->Media.BlockSize
  434. );
  435. // Put the device into Read Array mode
  436. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  437. // Readout the data
  438. AlignedCopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
  439. return EFI_SUCCESS;
  440. }
  441. EFI_STATUS
  442. NorFlashRead (
  443. IN NOR_FLASH_INSTANCE *Instance,
  444. IN EFI_LBA Lba,
  445. IN UINTN Offset,
  446. IN UINTN BufferSizeInBytes,
  447. OUT VOID *Buffer
  448. )
  449. {
  450. UINTN StartAddress;
  451. // The buffer must be valid
  452. if (Buffer == NULL) {
  453. return EFI_INVALID_PARAMETER;
  454. }
  455. // Return if we have not any byte to read
  456. if (BufferSizeInBytes == 0) {
  457. return EFI_SUCCESS;
  458. }
  459. if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {
  460. DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
  461. return EFI_INVALID_PARAMETER;
  462. }
  463. // Get the address to start reading from
  464. StartAddress = GET_NOR_BLOCK_ADDRESS (
  465. Instance->RegionBaseAddress,
  466. Lba,
  467. Instance->Media.BlockSize
  468. );
  469. // Put the device into Read Array mode
  470. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  471. // Readout the data
  472. AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
  473. return EFI_SUCCESS;
  474. }
  475. /*
  476. Write a full or portion of a block. It must not span block boundaries; that is,
  477. Offset + *NumBytes <= Instance->Media.BlockSize.
  478. */
  479. EFI_STATUS
  480. NorFlashWriteSingleBlock (
  481. IN NOR_FLASH_INSTANCE *Instance,
  482. IN EFI_LBA Lba,
  483. IN UINTN Offset,
  484. IN OUT UINTN *NumBytes,
  485. IN UINT8 *Buffer
  486. )
  487. {
  488. EFI_STATUS TempStatus;
  489. UINT32 Tmp;
  490. UINT32 TmpBuf;
  491. UINT32 WordToWrite;
  492. UINT32 Mask;
  493. BOOLEAN DoErase;
  494. UINTN BytesToWrite;
  495. UINTN CurOffset;
  496. UINTN WordAddr;
  497. UINTN BlockSize;
  498. UINTN BlockAddress;
  499. UINTN PrevBlockAddress;
  500. PrevBlockAddress = 0;
  501. DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
  502. // Detect WriteDisabled state
  503. if (Instance->Media.ReadOnly == TRUE) {
  504. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
  505. // It is in WriteDisabled state, return an error right away
  506. return EFI_ACCESS_DENIED;
  507. }
  508. // Cache the block size to avoid de-referencing pointers all the time
  509. BlockSize = Instance->Media.BlockSize;
  510. // The write must not span block boundaries.
  511. // We need to check each variable individually because adding two large values together overflows.
  512. if ((Offset >= BlockSize) ||
  513. (*NumBytes > BlockSize) ||
  514. ((Offset + *NumBytes) > BlockSize))
  515. {
  516. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
  517. return EFI_BAD_BUFFER_SIZE;
  518. }
  519. // We must have some bytes to write
  520. if (*NumBytes == 0) {
  521. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
  522. return EFI_BAD_BUFFER_SIZE;
  523. }
  524. // Pick 128bytes as a good start for word operations as opposed to erasing the
  525. // block and writing the data regardless if an erase is really needed.
  526. // It looks like most individual NV variable writes are smaller than 128bytes.
  527. if (*NumBytes <= 128) {
  528. // Check to see if we need to erase before programming the data into NOR.
  529. // If the destination bits are only changing from 1s to 0s we can just write.
  530. // After a block is erased all bits in the block is set to 1.
  531. // If any byte requires us to erase we just give up and rewrite all of it.
  532. DoErase = FALSE;
  533. BytesToWrite = *NumBytes;
  534. CurOffset = Offset;
  535. while (BytesToWrite > 0) {
  536. // Read full word from NOR, splice as required. A word is the smallest
  537. // unit we can write.
  538. TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof (Tmp), &Tmp);
  539. if (EFI_ERROR (TempStatus)) {
  540. return EFI_DEVICE_ERROR;
  541. }
  542. // Physical address of word in NOR to write.
  543. WordAddr = (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (
  544. Instance->RegionBaseAddress,
  545. Lba,
  546. BlockSize
  547. );
  548. // The word of data that is to be written.
  549. TmpBuf = *((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));
  550. // First do word aligned chunks.
  551. if ((CurOffset & 0x3) == 0) {
  552. if (BytesToWrite >= 4) {
  553. // Is the destination still in 'erased' state?
  554. if (~Tmp != 0) {
  555. // Check to see if we are only changing bits to zero.
  556. if ((Tmp ^ TmpBuf) & TmpBuf) {
  557. DoErase = TRUE;
  558. break;
  559. }
  560. }
  561. // Write this word to NOR
  562. WordToWrite = TmpBuf;
  563. CurOffset += sizeof (TmpBuf);
  564. BytesToWrite -= sizeof (TmpBuf);
  565. } else {
  566. // BytesToWrite < 4. Do small writes and left-overs
  567. Mask = ~((~0) << (BytesToWrite * 8));
  568. // Mask out the bytes we want.
  569. TmpBuf &= Mask;
  570. // Is the destination still in 'erased' state?
  571. if ((Tmp & Mask) != Mask) {
  572. // Check to see if we are only changing bits to zero.
  573. if ((Tmp ^ TmpBuf) & TmpBuf) {
  574. DoErase = TRUE;
  575. break;
  576. }
  577. }
  578. // Merge old and new data. Write merged word to NOR
  579. WordToWrite = (Tmp & ~Mask) | TmpBuf;
  580. CurOffset += BytesToWrite;
  581. BytesToWrite = 0;
  582. }
  583. } else {
  584. // Do multiple words, but starting unaligned.
  585. if (BytesToWrite > (4 - (CurOffset & 0x3))) {
  586. Mask = ((~0) << ((CurOffset & 0x3) * 8));
  587. // Mask out the bytes we want.
  588. TmpBuf &= Mask;
  589. // Is the destination still in 'erased' state?
  590. if ((Tmp & Mask) != Mask) {
  591. // Check to see if we are only changing bits to zero.
  592. if ((Tmp ^ TmpBuf) & TmpBuf) {
  593. DoErase = TRUE;
  594. break;
  595. }
  596. }
  597. // Merge old and new data. Write merged word to NOR
  598. WordToWrite = (Tmp & ~Mask) | TmpBuf;
  599. BytesToWrite -= (4 - (CurOffset & 0x3));
  600. CurOffset += (4 - (CurOffset & 0x3));
  601. } else {
  602. // Unaligned and fits in one word.
  603. Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
  604. // Mask out the bytes we want.
  605. TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
  606. // Is the destination still in 'erased' state?
  607. if ((Tmp & Mask) != Mask) {
  608. // Check to see if we are only changing bits to zero.
  609. if ((Tmp ^ TmpBuf) & TmpBuf) {
  610. DoErase = TRUE;
  611. break;
  612. }
  613. }
  614. // Merge old and new data. Write merged word to NOR
  615. WordToWrite = (Tmp & ~Mask) | TmpBuf;
  616. CurOffset += BytesToWrite;
  617. BytesToWrite = 0;
  618. }
  619. }
  620. //
  621. // Write the word to NOR.
  622. //
  623. BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
  624. if (BlockAddress != PrevBlockAddress) {
  625. TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
  626. if (EFI_ERROR (TempStatus)) {
  627. return EFI_DEVICE_ERROR;
  628. }
  629. PrevBlockAddress = BlockAddress;
  630. }
  631. TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
  632. if (EFI_ERROR (TempStatus)) {
  633. return EFI_DEVICE_ERROR;
  634. }
  635. }
  636. // Exit if we got here and could write all the data. Otherwise do the
  637. // Erase-Write cycle.
  638. if (!DoErase) {
  639. return EFI_SUCCESS;
  640. }
  641. }
  642. // Check we did get some memory. Buffer is BlockSize.
  643. if (Instance->ShadowBuffer == NULL) {
  644. DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
  645. return EFI_DEVICE_ERROR;
  646. }
  647. // Read NOR Flash data into shadow buffer
  648. TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
  649. if (EFI_ERROR (TempStatus)) {
  650. // Return one of the pre-approved error statuses
  651. return EFI_DEVICE_ERROR;
  652. }
  653. // Put the data at the appropriate location inside the buffer area
  654. CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
  655. // Write the modified buffer back to the NorFlash
  656. TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
  657. if (EFI_ERROR (TempStatus)) {
  658. // Return one of the pre-approved error statuses
  659. return EFI_DEVICE_ERROR;
  660. }
  661. return EFI_SUCCESS;
  662. }
  663. /*
  664. Although DiskIoDxe will automatically install the DiskIO protocol whenever
  665. we install the BlockIO protocol, its implementation is sub-optimal as it reads
  666. and writes entire blocks using the BlockIO protocol. In fact we can access
  667. NOR flash with a finer granularity than that, so we can improve performance
  668. by directly producing the DiskIO protocol.
  669. */
  670. /**
  671. Read BufferSize bytes from Offset into Buffer.
  672. @param This Protocol instance pointer.
  673. @param MediaId Id of the media, changes every time the media is replaced.
  674. @param Offset The starting byte offset to read from
  675. @param BufferSize Size of Buffer
  676. @param Buffer Buffer containing read data
  677. @retval EFI_SUCCESS The data was read correctly from the device.
  678. @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
  679. @retval EFI_NO_MEDIA There is no media in the device.
  680. @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
  681. @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
  682. valid for the device.
  683. **/
  684. EFI_STATUS
  685. EFIAPI
  686. NorFlashDiskIoReadDisk (
  687. IN EFI_DISK_IO_PROTOCOL *This,
  688. IN UINT32 MediaId,
  689. IN UINT64 DiskOffset,
  690. IN UINTN BufferSize,
  691. OUT VOID *Buffer
  692. )
  693. {
  694. NOR_FLASH_INSTANCE *Instance;
  695. UINT32 BlockSize;
  696. UINT32 BlockOffset;
  697. EFI_LBA Lba;
  698. Instance = INSTANCE_FROM_DISKIO_THIS (This);
  699. if (MediaId != Instance->Media.MediaId) {
  700. return EFI_MEDIA_CHANGED;
  701. }
  702. BlockSize = Instance->Media.BlockSize;
  703. Lba = (EFI_LBA)DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
  704. return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);
  705. }
  706. /**
  707. Writes a specified number of bytes to a device.
  708. @param This Indicates a pointer to the calling context.
  709. @param MediaId ID of the medium to be written.
  710. @param Offset The starting byte offset on the logical block I/O device to write.
  711. @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
  712. @param Buffer A pointer to the buffer containing the data to be written.
  713. @retval EFI_SUCCESS The data was written correctly to the device.
  714. @retval EFI_WRITE_PROTECTED The device can not be written to.
  715. @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
  716. @retval EFI_NO_MEDIA There is no media in the device.
  717. @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
  718. @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
  719. valid for the device.
  720. **/
  721. EFI_STATUS
  722. EFIAPI
  723. NorFlashDiskIoWriteDisk (
  724. IN EFI_DISK_IO_PROTOCOL *This,
  725. IN UINT32 MediaId,
  726. IN UINT64 DiskOffset,
  727. IN UINTN BufferSize,
  728. IN VOID *Buffer
  729. )
  730. {
  731. NOR_FLASH_INSTANCE *Instance;
  732. UINT32 BlockSize;
  733. UINT32 BlockOffset;
  734. EFI_LBA Lba;
  735. UINTN RemainingBytes;
  736. UINTN WriteSize;
  737. EFI_STATUS Status;
  738. Instance = INSTANCE_FROM_DISKIO_THIS (This);
  739. if (MediaId != Instance->Media.MediaId) {
  740. return EFI_MEDIA_CHANGED;
  741. }
  742. BlockSize = Instance->Media.BlockSize;
  743. Lba = (EFI_LBA)DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
  744. RemainingBytes = BufferSize;
  745. // Write either all the remaining bytes, or the number of bytes that bring
  746. // us up to a block boundary, whichever is less.
  747. // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
  748. // block boundary (even if it is already on one).
  749. WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);
  750. do {
  751. if (WriteSize == BlockSize) {
  752. // Write a full block
  753. Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32));
  754. } else {
  755. // Write a partial block
  756. Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer);
  757. }
  758. if (EFI_ERROR (Status)) {
  759. return Status;
  760. }
  761. // Now continue writing either all the remaining bytes or single blocks.
  762. RemainingBytes -= WriteSize;
  763. Buffer = (UINT8 *)Buffer + WriteSize;
  764. Lba++;
  765. BlockOffset = 0;
  766. WriteSize = MIN (RemainingBytes, BlockSize);
  767. } while (RemainingBytes);
  768. return Status;
  769. }
  770. EFI_STATUS
  771. NorFlashReset (
  772. IN NOR_FLASH_INSTANCE *Instance
  773. )
  774. {
  775. // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
  776. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  777. return EFI_SUCCESS;
  778. }
  779. /**
  780. Fixup internal data so that EFI can be call in virtual mode.
  781. Call the passed in Child Notify event and convert any pointers in
  782. lib to virtual mode.
  783. @param[in] Event The Event that is being processed
  784. @param[in] Context Event Context
  785. **/
  786. VOID
  787. EFIAPI
  788. NorFlashVirtualNotifyEvent (
  789. IN EFI_EVENT Event,
  790. IN VOID *Context
  791. )
  792. {
  793. UINTN Index;
  794. for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
  795. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress);
  796. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress);
  797. // Convert BlockIo protocol
  798. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);
  799. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);
  800. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);
  801. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);
  802. // Convert Fvb
  803. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
  804. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
  805. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
  806. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
  807. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read);
  808. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
  809. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write);
  810. if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
  811. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
  812. }
  813. }
  814. return;
  815. }