NorFlash.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /** @file NorFlashDxe.c
  2. Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
  3. Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
  4. Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <Library/BaseMemoryLib.h>
  8. #include <Library/MemoryAllocationLib.h>
  9. #include <Library/NorFlashInfoLib.h>
  10. #include <Library/PcdLib.h>
  11. #include <Library/UefiBootServicesTableLib.h>
  12. #include <Library/UefiLib.h>
  13. #include <Platform/MemoryMap.h>
  14. #include "NorFlash.h"
  15. #define FW_CODE_REGION_BASE SYNQUACER_SPI_NOR_BASE
  16. #define FW_CODE_REGION_SIZE (FW_ENV_REGION_BASE - FW_CODE_REGION_BASE)
  17. #define FW_ENV_REGION_BASE FixedPcdGet32 (PcdFlashNvStorageVariableBase)
  18. #define FW_ENV_REGION_SIZE (FixedPcdGet32 (PcdFlashNvStorageVariableSize) + \
  19. FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + \
  20. FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize))
  21. STATIC NOR_FLASH_DESCRIPTION mNorFlashDevices[] = {
  22. {
  23. // UEFI code region
  24. SYNQUACER_SPI_NOR_BASE, // device base
  25. FW_CODE_REGION_BASE, // region base
  26. FW_CODE_REGION_SIZE, // region size
  27. SIZE_64KB, // block size
  28. },
  29. {
  30. // Environment variable region
  31. SYNQUACER_SPI_NOR_BASE, // device base
  32. FW_ENV_REGION_BASE, // region base
  33. FW_ENV_REGION_SIZE, // region size
  34. SIZE_64KB, // block size
  35. },
  36. };
  37. STATIC CONST UINT16 mFip006NullCmdSeq[] = {
  38. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  39. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  40. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  41. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  42. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  43. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  44. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  45. CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE),
  46. };
  47. STATIC CONST CSDC_DEFINITION mN25qCSDCDefTable[] = {
  48. // Identification Operations
  49. { SPINOR_OP_RDID, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  50. CSDC_TRP_SINGLE },
  51. // Register Operations
  52. { SPINOR_OP_RDSR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  53. CSDC_TRP_SINGLE },
  54. { SPINOR_OP_WRSR, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE,
  55. CSDC_TRP_SINGLE },
  56. { SPINOR_OP_RD_ARRAY, TRUE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  57. CSDC_TRP_SINGLE },
  58. { SPINOR_OP_RDFSR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  59. CSDC_TRP_SINGLE },
  60. { SPINOR_OP_RD_NVCFG, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  61. CSDC_TRP_SINGLE },
  62. { SPINOR_OP_RD_VCR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  63. CSDC_TRP_SINGLE },
  64. { SPINOR_OP_RD_EVCR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  65. CSDC_TRP_SINGLE },
  66. // Read Operations
  67. { SPINOR_OP_READ_4B, TRUE, TRUE, FALSE, FALSE, CS_CFG_MBM_SINGLE,
  68. CSDC_TRP_SINGLE },
  69. // Write Operations
  70. { SPINOR_OP_PP_4B, TRUE, TRUE, FALSE, TRUE, CS_CFG_MBM_SINGLE,
  71. CSDC_TRP_SINGLE },
  72. // Erase Operations
  73. { SPINOR_OP_BE_4B, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE,
  74. CSDC_TRP_SINGLE },
  75. };
  76. STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
  77. NOR_FLASH_SIGNATURE, // Signature
  78. NULL, // Handle ... NEED TO BE FILLED
  79. FALSE, // Initialized
  80. NULL, // Initialize
  81. 0, // HostRegisterBaseAddress ... NEED TO BE FILLED
  82. 0, // DeviceBaseAddress ... NEED TO BE FILLED
  83. 0, // RegionBaseAddress ... NEED TO BE FILLED
  84. 0, // Size ... NEED TO BE FILLED
  85. 0, // BlockSize
  86. 0, // LastBlock
  87. 0, // StartLba
  88. 0, // OffsetLba
  89. {
  90. FvbGetAttributes, // GetAttributes
  91. FvbSetAttributes, // SetAttributes
  92. FvbGetPhysicalAddress, // GetPhysicalAddress
  93. FvbGetBlockSize, // GetBlockSize
  94. FvbRead, // Read
  95. FvbWrite, // Write
  96. FvbEraseBlocks, // EraseBlocks
  97. NULL, //ParentHandle
  98. }, // FvbProtoccol;
  99. NULL, // ShadowBuffer
  100. {
  101. {
  102. {
  103. HARDWARE_DEVICE_PATH,
  104. HW_VENDOR_DP,
  105. {
  106. (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
  107. (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
  108. }
  109. },
  110. { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } },
  111. },
  112. 0, // Index
  113. {
  114. END_DEVICE_PATH_TYPE,
  115. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  116. { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
  117. }
  118. }, // DevicePath
  119. 0 // Flags
  120. };
  121. EFI_STATUS
  122. NorFlashCreateInstance (
  123. IN UINTN HostRegisterBase,
  124. IN UINTN NorFlashDeviceBase,
  125. IN UINTN NorFlashRegionBase,
  126. IN UINTN NorFlashSize,
  127. IN UINT32 Index,
  128. IN UINT32 BlockSize,
  129. IN BOOLEAN HasVarStore,
  130. OUT NOR_FLASH_INSTANCE** NorFlashInstance
  131. )
  132. {
  133. EFI_STATUS Status;
  134. NOR_FLASH_INSTANCE* Instance;
  135. NOR_FLASH_INFO *FlashInfo;
  136. UINT8 JedecId[3];
  137. ASSERT(NorFlashInstance != NULL);
  138. Instance = AllocateRuntimeCopyPool (sizeof mNorFlashInstanceTemplate,
  139. &mNorFlashInstanceTemplate);
  140. if (Instance == NULL) {
  141. return EFI_OUT_OF_RESOURCES;
  142. }
  143. Instance->HostRegisterBaseAddress = HostRegisterBase;
  144. Instance->DeviceBaseAddress = NorFlashDeviceBase;
  145. Instance->RegionBaseAddress = NorFlashRegionBase;
  146. Instance->Size = NorFlashSize;
  147. Instance->BlockSize = BlockSize;
  148. Instance->LastBlock = (NorFlashSize / BlockSize) - 1;
  149. Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize;
  150. CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
  151. Instance->DevicePath.Index = (UINT8)Index;
  152. NorFlashReset (Instance);
  153. NorFlashReadID (Instance, JedecId);
  154. Status = NorFlashGetInfo (JedecId, &FlashInfo, FALSE);
  155. if (EFI_ERROR (Status)) {
  156. goto FreeInstance;
  157. }
  158. NorFlashPrintInfo (FlashInfo);
  159. Instance->Flags = 0;
  160. if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) {
  161. Instance->Flags = NOR_FLASH_POLL_FSR;
  162. }
  163. Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);
  164. if (Instance->ShadowBuffer == NULL) {
  165. Status = EFI_OUT_OF_RESOURCES;
  166. goto FreeInstance;
  167. }
  168. if (HasVarStore) {
  169. Instance->Initialize = NorFlashFvbInitialize;
  170. }
  171. *NorFlashInstance = Instance;
  172. FreePool (FlashInfo);
  173. return EFI_SUCCESS;
  174. FreeInstance:
  175. FreePool (Instance);
  176. return Status;
  177. }
  178. STATIC
  179. EFI_STATUS
  180. NorFlashSetHostCSDC (
  181. IN NOR_FLASH_INSTANCE *Instance,
  182. IN BOOLEAN ReadWrite,
  183. IN CONST UINT16 CSDC[ARRAY_SIZE (mFip006NullCmdSeq)]
  184. )
  185. {
  186. EFI_PHYSICAL_ADDRESS Dst;
  187. UINTN Index;
  188. Dst = Instance->HostRegisterBaseAddress
  189. + (ReadWrite ? FIP006_REG_CS_WR : FIP006_REG_CS_RD);
  190. for (Index = 0; Index < ARRAY_SIZE (mFip006NullCmdSeq); Index++) {
  191. MmioWrite16 (Dst + (Index << 1), CSDC[Index]);
  192. }
  193. return EFI_SUCCESS;
  194. }
  195. STATIC
  196. CONST CSDC_DEFINITION *
  197. NorFlashGetCmdDef (
  198. IN NOR_FLASH_INSTANCE *Instance,
  199. IN UINT8 Code
  200. )
  201. {
  202. CONST CSDC_DEFINITION *Cmd;
  203. UINTN Index;
  204. Cmd = NULL;
  205. for (Index = 0; Index < ARRAY_SIZE (mN25qCSDCDefTable); Index++) {
  206. if (Code == mN25qCSDCDefTable[Index].Code) {
  207. Cmd = &mN25qCSDCDefTable[Index];
  208. break;
  209. }
  210. }
  211. return Cmd;
  212. }
  213. STATIC
  214. EFI_STATUS
  215. GenCSDC (
  216. IN UINT8 Cmd,
  217. IN BOOLEAN AddrAccess,
  218. IN BOOLEAN AddrMode4Byte,
  219. IN BOOLEAN HighZ,
  220. IN UINT8 TransferMode,
  221. OUT UINT16 *CmdSeq
  222. )
  223. {
  224. UINTN Index;
  225. if (!CmdSeq) {
  226. return EFI_INVALID_PARAMETER;
  227. }
  228. Index = 0;
  229. CopyMem (CmdSeq, mFip006NullCmdSeq, sizeof (mFip006NullCmdSeq));
  230. CmdSeq[Index++] = CSDC (Cmd, CSDC_CONT_NON_CONTINUOUS, TransferMode,
  231. CSDC_DEC_LEAVE_ASIS);
  232. if (AddrAccess) {
  233. if (AddrMode4Byte) {
  234. CmdSeq[Index++] = CSDC (CSDC_ADDRESS_31_24, CSDC_CONT_NON_CONTINUOUS,
  235. TransferMode, CSDC_DEC_DECODE);
  236. }
  237. CmdSeq[Index++] = CSDC (CSDC_ADDRESS_23_16, CSDC_CONT_NON_CONTINUOUS,
  238. TransferMode, CSDC_DEC_DECODE);
  239. CmdSeq[Index++] = CSDC (CSDC_ADDRESS_15_8, CSDC_CONT_NON_CONTINUOUS,
  240. TransferMode, CSDC_DEC_DECODE);
  241. CmdSeq[Index++] = CSDC (CSDC_ADDRESS_7_0, CSDC_CONT_NON_CONTINUOUS,
  242. TransferMode, CSDC_DEC_DECODE);
  243. }
  244. if (HighZ) {
  245. CmdSeq[Index++] = CSDC (CSDC_HIGH_Z, CSDC_CONT_NON_CONTINUOUS,
  246. TransferMode, CSDC_DEC_DECODE);
  247. }
  248. return EFI_SUCCESS;
  249. }
  250. STATIC
  251. EFI_STATUS
  252. NorFlashSetHostCommand (
  253. IN NOR_FLASH_INSTANCE *Instance,
  254. IN UINT8 Code
  255. )
  256. {
  257. CONST CSDC_DEFINITION *Cmd;
  258. UINT16 CSDC[ARRAY_SIZE (mFip006NullCmdSeq)];
  259. Cmd = NorFlashGetCmdDef (Instance, Code);
  260. if (Cmd == NULL) {
  261. return EFI_INVALID_PARAMETER;
  262. }
  263. GenCSDC (
  264. Cmd->Code,
  265. Cmd->AddrAccess,
  266. Cmd->AddrMode4Byte,
  267. Cmd->HighZ,
  268. Cmd->CsdcTrp,
  269. CSDC
  270. );
  271. NorFlashSetHostCSDC (Instance, Cmd->ReadWrite, CSDC);
  272. return EFI_SUCCESS;
  273. }
  274. STATIC
  275. UINT8
  276. NorFlashReadStatusRegister (
  277. IN NOR_FLASH_INSTANCE *Instance
  278. )
  279. {
  280. UINT8 StatusRegister;
  281. NorFlashSetHostCommand (Instance, SPINOR_OP_RDSR);
  282. StatusRegister = MmioRead8 (Instance->RegionBaseAddress);
  283. NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B);
  284. return StatusRegister;
  285. }
  286. STATIC
  287. EFI_STATUS
  288. NorFlashWaitProgramErase (
  289. IN NOR_FLASH_INSTANCE *Instance
  290. )
  291. {
  292. BOOLEAN SRegDone;
  293. BOOLEAN FSRegDone;
  294. DEBUG ((DEBUG_BLKIO, "NorFlashWaitProgramErase()\n"));
  295. do {
  296. SRegDone = (NorFlashReadStatusRegister (Instance) & SPINOR_SR_WIP) == 0;
  297. FSRegDone = TRUE;
  298. if (Instance->Flags & NOR_FLASH_POLL_FSR) {
  299. NorFlashSetHostCommand (Instance, SPINOR_OP_RDFSR);
  300. FSRegDone = (MmioRead8 (Instance->RegionBaseAddress) &
  301. SPINOR_FSR_READY) != 0;
  302. }
  303. } while (!SRegDone || !FSRegDone);
  304. NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B);
  305. return EFI_SUCCESS;
  306. }
  307. // TODO: implement lock checking
  308. STATIC
  309. BOOLEAN
  310. NorFlashBlockIsLocked (
  311. IN NOR_FLASH_INSTANCE *Instance,
  312. IN UINTN BlockAddress
  313. )
  314. {
  315. return FALSE;
  316. }
  317. // TODO: implement sector unlocking
  318. STATIC
  319. EFI_STATUS
  320. NorFlashUnlockSingleBlock (
  321. IN NOR_FLASH_INSTANCE *Instance,
  322. IN UINTN BlockAddress
  323. )
  324. {
  325. return EFI_SUCCESS;
  326. }
  327. STATIC
  328. EFI_STATUS
  329. NorFlashUnlockSingleBlockIfNecessary (
  330. IN NOR_FLASH_INSTANCE *Instance,
  331. IN UINTN BlockAddress
  332. )
  333. {
  334. EFI_STATUS Status;
  335. Status = EFI_SUCCESS;
  336. if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) {
  337. Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
  338. }
  339. return Status;
  340. }
  341. STATIC
  342. EFI_STATUS
  343. NorFlashEnableWrite (
  344. IN NOR_FLASH_INSTANCE *Instance
  345. )
  346. {
  347. EFI_STATUS Status;
  348. UINT8 StatusRegister;
  349. UINTN Retry;
  350. DEBUG ((DEBUG_BLKIO, "NorFlashEnableWrite()\n"));
  351. Status = EFI_DEVICE_ERROR;
  352. Retry = NOR_FLASH_ERASE_RETRY;
  353. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  354. while (Retry > 0 && EFI_ERROR (Status)) {
  355. MmioWrite8 (Instance->RegionBaseAddress, SPINOR_OP_WREN);
  356. MemoryFence ();
  357. StatusRegister = NorFlashReadStatusRegister (Instance);
  358. Status = (StatusRegister & BIT1) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
  359. Retry--;
  360. }
  361. return Status;
  362. }
  363. STATIC
  364. EFI_STATUS
  365. NorFlashDisableWrite (
  366. IN NOR_FLASH_INSTANCE *Instance
  367. )
  368. {
  369. EFI_STATUS Status;
  370. UINT8 StatusRegister;
  371. UINTN Retry;
  372. DEBUG ((DEBUG_BLKIO, "NorFlashDisableWrite()\n"));
  373. Status = EFI_DEVICE_ERROR;
  374. Retry = NOR_FLASH_ERASE_RETRY;
  375. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  376. while (Retry > 0 && EFI_ERROR (Status)) {
  377. MmioWrite8 (Instance->RegionBaseAddress, SPINOR_OP_WRDIS);
  378. MemoryFence ();
  379. StatusRegister = NorFlashReadStatusRegister (Instance);
  380. Status = (StatusRegister & BIT1) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
  381. Retry--;
  382. }
  383. return Status;
  384. }
  385. /**
  386. * The following function presumes that the block has already been unlocked.
  387. **/
  388. STATIC
  389. EFI_STATUS
  390. NorFlashEraseSingleBlock (
  391. IN NOR_FLASH_INSTANCE *Instance,
  392. IN UINTN BlockAddress
  393. )
  394. {
  395. DEBUG ((DEBUG_BLKIO, "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n",
  396. BlockAddress));
  397. if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
  398. return EFI_DEVICE_ERROR;
  399. }
  400. //
  401. // The virtual address chosen by the OS may have a different offset modulo
  402. // 16 MB than the physical address, so we need to subtract the region base
  403. // address before we can mask off a block index. Note that the relative
  404. // offset between device base address and region base address may have changed
  405. // as well, so we cannot use the device base address directly.
  406. //
  407. BlockAddress -= Instance->RegionBaseAddress;
  408. BlockAddress += Instance->OffsetLba * Instance->BlockSize;
  409. NorFlashSetHostCommand (Instance, SPINOR_OP_BE_4B);
  410. MmioWrite32 (Instance->DeviceBaseAddress, SwapBytes32 (BlockAddress));
  411. NorFlashWaitProgramErase (Instance);
  412. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  413. if (EFI_ERROR (NorFlashDisableWrite (Instance))) {
  414. return EFI_DEVICE_ERROR;
  415. }
  416. return EFI_SUCCESS;
  417. }
  418. /**
  419. * This function unlock and erase an entire NOR Flash block.
  420. **/
  421. EFI_STATUS
  422. NorFlashUnlockAndEraseSingleBlock (
  423. IN NOR_FLASH_INSTANCE *Instance,
  424. IN UINTN BlockAddress
  425. )
  426. {
  427. EFI_STATUS Status;
  428. UINTN Index;
  429. NOR_FLASH_LOCK_CONTEXT Lock;
  430. NorFlashLock (&Lock);
  431. Index = 0;
  432. // The block erase might fail a first time (SW bug ?). Retry it ...
  433. do {
  434. // Unlock the block if we have to
  435. Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
  436. if (EFI_ERROR (Status)) {
  437. break;
  438. }
  439. Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
  440. Index++;
  441. } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
  442. if (Index == NOR_FLASH_ERASE_RETRY) {
  443. DEBUG ((DEBUG_ERROR,
  444. "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n",
  445. BlockAddress,Index));
  446. }
  447. NorFlashUnlock (&Lock);
  448. return Status;
  449. }
  450. STATIC
  451. EFI_STATUS
  452. NorFlashWriteSingleWord (
  453. IN NOR_FLASH_INSTANCE *Instance,
  454. IN UINTN WordAddress,
  455. IN UINT32 WriteData
  456. )
  457. {
  458. EFI_STATUS Status;
  459. DEBUG ((DEBUG_BLKIO,
  460. "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n",
  461. WordAddress, WriteData));
  462. Status = EFI_SUCCESS;
  463. if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
  464. return EFI_DEVICE_ERROR;
  465. }
  466. NorFlashSetHostCommand (Instance, SPINOR_OP_PP_4B);
  467. MmioWrite32 (WordAddress, WriteData);
  468. NorFlashWaitProgramErase (Instance);
  469. NorFlashDisableWrite (Instance);
  470. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  471. return Status;
  472. }
  473. STATIC
  474. EFI_STATUS
  475. NorFlashWriteFullBlock (
  476. IN NOR_FLASH_INSTANCE *Instance,
  477. IN EFI_LBA Lba,
  478. IN UINT32 *DataBuffer,
  479. IN UINT32 BlockSizeInWords
  480. )
  481. {
  482. EFI_STATUS Status;
  483. UINTN WordAddress;
  484. UINT32 WordIndex;
  485. UINTN BlockAddress;
  486. NOR_FLASH_LOCK_CONTEXT Lock;
  487. Status = EFI_SUCCESS;
  488. // Get the physical address of the block
  489. BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
  490. BlockSizeInWords * 4);
  491. // Start writing from the first address at the start of the block
  492. WordAddress = BlockAddress;
  493. NorFlashLock (&Lock);
  494. Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
  495. if (EFI_ERROR (Status)) {
  496. DEBUG ((DEBUG_ERROR,
  497. "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n",
  498. BlockAddress));
  499. goto EXIT;
  500. }
  501. for (WordIndex=0;
  502. WordIndex < BlockSizeInWords;
  503. WordIndex++, DataBuffer++, WordAddress += 4) {
  504. Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
  505. if (EFI_ERROR (Status)) {
  506. goto EXIT;
  507. }
  508. }
  509. EXIT:
  510. NorFlashUnlock (&Lock);
  511. if (EFI_ERROR (Status)) {
  512. DEBUG ((DEBUG_ERROR,
  513. "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n",
  514. WordAddress, Status));
  515. }
  516. return Status;
  517. }
  518. EFI_STATUS
  519. NorFlashWriteBlocks (
  520. IN NOR_FLASH_INSTANCE *Instance,
  521. IN EFI_LBA Lba,
  522. IN UINTN BufferSizeInBytes,
  523. IN VOID *Buffer
  524. )
  525. {
  526. UINT32 *pWriteBuffer;
  527. EFI_STATUS Status = EFI_SUCCESS;
  528. EFI_LBA CurrentBlock;
  529. UINT32 BlockSizeInWords;
  530. UINT32 NumBlocks;
  531. UINT32 BlockCount;
  532. // The buffer must be valid
  533. if (Buffer == NULL) {
  534. return EFI_INVALID_PARAMETER;
  535. }
  536. // We must have some bytes to read
  537. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n",
  538. BufferSizeInBytes));
  539. if (BufferSizeInBytes == 0) {
  540. return EFI_BAD_BUFFER_SIZE;
  541. }
  542. // The size of the buffer must be a multiple of the block size
  543. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n",
  544. Instance->BlockSize));
  545. if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
  546. return EFI_BAD_BUFFER_SIZE;
  547. }
  548. // All blocks must be within the device
  549. NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize ;
  550. DEBUG ((DEBUG_BLKIO,
  551. "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks,
  552. Instance->LastBlock, Lba));
  553. if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
  554. DEBUG ((DEBUG_ERROR,
  555. "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
  556. return EFI_INVALID_PARAMETER;
  557. }
  558. ASSERT (((UINTN)Buffer % sizeof (UINT32)) == 0);
  559. BlockSizeInWords = Instance->BlockSize / 4;
  560. // Because the target *Buffer is a pointer to VOID, we must put
  561. // all the data into a pointer to a proper data type, so use *ReadBuffer
  562. pWriteBuffer = (UINT32 *)Buffer;
  563. CurrentBlock = Lba;
  564. for (BlockCount = 0;
  565. BlockCount < NumBlocks;
  566. BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords) {
  567. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n",
  568. (UINTN)CurrentBlock));
  569. Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer,
  570. BlockSizeInWords);
  571. if (EFI_ERROR (Status)) {
  572. break;
  573. }
  574. }
  575. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
  576. return Status;
  577. }
  578. EFI_STATUS
  579. NorFlashReadBlocks (
  580. IN NOR_FLASH_INSTANCE *Instance,
  581. IN EFI_LBA Lba,
  582. IN UINTN BufferSizeInBytes,
  583. OUT VOID *Buffer
  584. )
  585. {
  586. UINT32 NumBlocks;
  587. UINTN StartAddress;
  588. DEBUG ((DEBUG_BLKIO,
  589. "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
  590. BufferSizeInBytes, Instance->BlockSize, Instance->LastBlock,
  591. Lba));
  592. // The buffer must be valid
  593. if (Buffer == NULL) {
  594. return EFI_INVALID_PARAMETER;
  595. }
  596. // Return if we have not any byte to read
  597. if (BufferSizeInBytes == 0) {
  598. return EFI_SUCCESS;
  599. }
  600. // The size of the buffer must be a multiple of the block size
  601. if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
  602. return EFI_BAD_BUFFER_SIZE;
  603. }
  604. // All blocks must be within the device
  605. NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize ;
  606. if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
  607. DEBUG ((DEBUG_ERROR,
  608. "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
  609. return EFI_INVALID_PARAMETER;
  610. }
  611. // Get the address to start reading from
  612. StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
  613. Instance->BlockSize);
  614. // Put the device into Read Array mode
  615. NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B);
  616. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  617. // Readout the data
  618. CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
  619. return EFI_SUCCESS;
  620. }
  621. EFI_STATUS
  622. NorFlashRead (
  623. IN NOR_FLASH_INSTANCE *Instance,
  624. IN EFI_LBA Lba,
  625. IN UINTN Offset,
  626. IN UINTN BufferSizeInBytes,
  627. OUT VOID *Buffer
  628. )
  629. {
  630. UINTN StartAddress;
  631. // The buffer must be valid
  632. if (Buffer == NULL) {
  633. return EFI_INVALID_PARAMETER;
  634. }
  635. // Return if we have not any byte to read
  636. if (BufferSizeInBytes == 0) {
  637. return EFI_SUCCESS;
  638. }
  639. if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) >
  640. Instance->Size) {
  641. DEBUG ((DEBUG_ERROR,
  642. "NorFlashRead: ERROR - Read will exceed device size.\n"));
  643. return EFI_INVALID_PARAMETER;
  644. }
  645. // Get the address to start reading from
  646. StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
  647. Instance->BlockSize);
  648. // Put the device into Read Array mode
  649. NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B);
  650. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  651. // Readout the data
  652. CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);
  653. return EFI_SUCCESS;
  654. }
  655. /*
  656. Write a full or portion of a block. It must not span block boundaries;
  657. that is, Offset + *NumBytes <= Instance->BlockSize.
  658. */
  659. EFI_STATUS
  660. NorFlashWriteSingleBlock (
  661. IN NOR_FLASH_INSTANCE *Instance,
  662. IN EFI_LBA Lba,
  663. IN UINTN Offset,
  664. IN OUT UINTN *NumBytes,
  665. IN UINT8 *Buffer
  666. )
  667. {
  668. EFI_STATUS TempStatus;
  669. UINT32 Tmp;
  670. UINT32 TmpBuf;
  671. UINT32 WordToWrite;
  672. UINT32 Mask;
  673. BOOLEAN DoErase;
  674. UINTN BytesToWrite;
  675. UINTN CurOffset;
  676. UINTN WordAddr;
  677. UINTN BlockSize;
  678. UINTN BlockAddress;
  679. UINTN PrevBlockAddress;
  680. PrevBlockAddress = 0;
  681. if (!Instance->Initialized && Instance->Initialize) {
  682. Instance->Initialize(Instance);
  683. }
  684. DEBUG ((DEBUG_BLKIO,
  685. "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
  686. Lba, Offset, *NumBytes, Buffer));
  687. // Cache the block size to avoid de-referencing pointers all the time
  688. BlockSize = Instance->BlockSize;
  689. // The write must not span block boundaries.
  690. // We need to check each variable individually because adding two large
  691. // values together overflows.
  692. if (Offset >= BlockSize ||
  693. *NumBytes > BlockSize ||
  694. (Offset + *NumBytes) > BlockSize) {
  695. DEBUG ((DEBUG_ERROR,
  696. "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
  697. Offset, *NumBytes, BlockSize ));
  698. return EFI_BAD_BUFFER_SIZE;
  699. }
  700. // We must have some bytes to write
  701. if (*NumBytes == 0) {
  702. DEBUG ((DEBUG_ERROR,
  703. "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
  704. Offset, *NumBytes, BlockSize ));
  705. return EFI_BAD_BUFFER_SIZE;
  706. }
  707. // Pick 128bytes as a good start for word operations as opposed to erasing the
  708. // block and writing the data regardless if an erase is really needed.
  709. // It looks like most individual NV variable writes are smaller than 128bytes.
  710. if (*NumBytes <= 128) {
  711. // Check to see if we need to erase before programming the data into NOR.
  712. // If the destination bits are only changing from 1s to 0s we can just write.
  713. // After a block is erased all bits in the block is set to 1.
  714. // If any byte requires us to erase we just give up and rewrite all of it.
  715. DoErase = FALSE;
  716. BytesToWrite = *NumBytes;
  717. CurOffset = Offset;
  718. while (BytesToWrite > 0) {
  719. // Read full word from NOR, splice as required. A word is the smallest
  720. // unit we can write.
  721. TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp),
  722. &Tmp);
  723. if (EFI_ERROR (TempStatus)) {
  724. return EFI_DEVICE_ERROR;
  725. }
  726. // Physical address of word in NOR to write.
  727. WordAddr = (CurOffset & ~(0x3)) +
  728. GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
  729. BlockSize);
  730. // The word of data that is to be written.
  731. TmpBuf = ReadUnaligned32 ((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));
  732. // First do word aligned chunks.
  733. if ((CurOffset & 0x3) == 0) {
  734. if (BytesToWrite >= 4) {
  735. // Is the destination still in 'erased' state?
  736. if (~Tmp != 0) {
  737. // Check to see if we are only changing bits to zero.
  738. if ((Tmp ^ TmpBuf) & TmpBuf) {
  739. DoErase = TRUE;
  740. break;
  741. }
  742. }
  743. // Write this word to NOR
  744. WordToWrite = TmpBuf;
  745. CurOffset += sizeof(TmpBuf);
  746. BytesToWrite -= sizeof(TmpBuf);
  747. } else {
  748. // BytesToWrite < 4. Do small writes and left-overs
  749. Mask = ~((~0) << (BytesToWrite * 8));
  750. // Mask out the bytes we want.
  751. TmpBuf &= Mask;
  752. // Is the destination still in 'erased' state?
  753. if ((Tmp & Mask) != Mask) {
  754. // Check to see if we are only changing bits to zero.
  755. if ((Tmp ^ TmpBuf) & TmpBuf) {
  756. DoErase = TRUE;
  757. break;
  758. }
  759. }
  760. // Merge old and new data. Write merged word to NOR
  761. WordToWrite = (Tmp & ~Mask) | TmpBuf;
  762. CurOffset += BytesToWrite;
  763. BytesToWrite = 0;
  764. }
  765. } else {
  766. // Do multiple words, but starting unaligned.
  767. if (BytesToWrite > (4 - (CurOffset & 0x3))) {
  768. Mask = ((~0) << ((CurOffset & 0x3) * 8));
  769. // Mask out the bytes we want.
  770. TmpBuf &= Mask;
  771. // Is the destination still in 'erased' state?
  772. if ((Tmp & Mask) != Mask) {
  773. // Check to see if we are only changing bits to zero.
  774. if ((Tmp ^ TmpBuf) & TmpBuf) {
  775. DoErase = TRUE;
  776. break;
  777. }
  778. }
  779. // Merge old and new data. Write merged word to NOR
  780. WordToWrite = (Tmp & ~Mask) | TmpBuf;
  781. BytesToWrite -= (4 - (CurOffset & 0x3));
  782. CurOffset += (4 - (CurOffset & 0x3));
  783. } else {
  784. // Unaligned and fits in one word.
  785. Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
  786. // Mask out the bytes we want.
  787. TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
  788. // Is the destination still in 'erased' state?
  789. if ((Tmp & Mask) != Mask) {
  790. // Check to see if we are only changing bits to zero.
  791. if ((Tmp ^ TmpBuf) & TmpBuf) {
  792. DoErase = TRUE;
  793. break;
  794. }
  795. }
  796. // Merge old and new data. Write merged word to NOR
  797. WordToWrite = (Tmp & ~Mask) | TmpBuf;
  798. CurOffset += BytesToWrite;
  799. BytesToWrite = 0;
  800. }
  801. }
  802. //
  803. // Write the word to NOR.
  804. //
  805. BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
  806. BlockSize);
  807. if (BlockAddress != PrevBlockAddress) {
  808. TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance,
  809. BlockAddress);
  810. if (EFI_ERROR (TempStatus)) {
  811. return EFI_DEVICE_ERROR;
  812. }
  813. PrevBlockAddress = BlockAddress;
  814. }
  815. TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
  816. if (EFI_ERROR (TempStatus)) {
  817. return EFI_DEVICE_ERROR;
  818. }
  819. }
  820. // Exit if we got here and could write all the data. Otherwise do the
  821. // Erase-Write cycle.
  822. if (!DoErase) {
  823. return EFI_SUCCESS;
  824. }
  825. }
  826. // Check we did get some memory. Buffer is BlockSize.
  827. if (Instance->ShadowBuffer == NULL) {
  828. DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
  829. return EFI_DEVICE_ERROR;
  830. }
  831. // Read NOR Flash data into shadow buffer
  832. TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize,
  833. Instance->ShadowBuffer);
  834. if (EFI_ERROR (TempStatus)) {
  835. // Return one of the pre-approved error statuses
  836. return EFI_DEVICE_ERROR;
  837. }
  838. // Put the data at the appropriate location inside the buffer area
  839. CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
  840. // Write the modified buffer back to the NorFlash
  841. TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize,
  842. Instance->ShadowBuffer);
  843. if (EFI_ERROR (TempStatus)) {
  844. // Return one of the pre-approved error statuses
  845. return EFI_DEVICE_ERROR;
  846. }
  847. return EFI_SUCCESS;
  848. }
  849. EFI_STATUS
  850. NorFlashReset (
  851. IN NOR_FLASH_INSTANCE *Instance
  852. )
  853. {
  854. FIP006_CS_CFG CsCfg;
  855. DEBUG ((DEBUG_BLKIO, "NorFlashReset()\n"));
  856. CsCfg.Raw = MmioRead32 (Instance->HostRegisterBaseAddress +
  857. FIP006_REG_CS_CFG);
  858. CsCfg.Reg.MBM = CS_CFG_MBM_SINGLE;
  859. CsCfg.Reg.SRAM = CS_CFG_SRAM_RW;
  860. MmioWrite32 (Instance->HostRegisterBaseAddress + FIP006_REG_CS_CFG,
  861. CsCfg.Raw);
  862. NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B);
  863. NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
  864. return EFI_SUCCESS;
  865. }
  866. EFI_STATUS
  867. NorFlashReadID (
  868. IN NOR_FLASH_INSTANCE *Instance,
  869. OUT UINT8 JedecId[3]
  870. )
  871. {
  872. if (Instance == NULL || JedecId == NULL) {
  873. return EFI_INVALID_PARAMETER;
  874. }
  875. NorFlashSetHostCommand (Instance, SPINOR_OP_RDID);
  876. JedecId[0] = MmioRead8 (Instance->DeviceBaseAddress);
  877. JedecId[1] = MmioRead8 (Instance->DeviceBaseAddress + 1);
  878. JedecId[2] = MmioRead8 (Instance->DeviceBaseAddress + 2);
  879. NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B);
  880. return EFI_SUCCESS;
  881. }
  882. EFI_STATUS
  883. NorFlashPlatformGetDevices (
  884. OUT NOR_FLASH_DESCRIPTION **NorFlashDevices,
  885. OUT UINT32 *Count
  886. )
  887. {
  888. if (NorFlashDevices == NULL ||
  889. Count == NULL) {
  890. return EFI_INVALID_PARAMETER;
  891. }
  892. *Count = ARRAY_SIZE (mNorFlashDevices);
  893. *NorFlashDevices = mNorFlashDevices;
  894. return EFI_SUCCESS;
  895. }