core_flash.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. * Copyright (c) 2022 OpenLuat & AirM2M
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. * this software and associated documentation files (the "Software"), to deal in
  6. * the Software without restriction, including without limitation the rights to
  7. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8. * the Software, and to permit persons to whom the Software is furnished to do so,
  9. * subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in all
  12. * copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  16. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  17. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  18. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. */
  21. #include "bl_inc.h"
  22. typedef struct
  23. {
  24. uint8_t Instruction;
  25. QSPI_BusModeTypeDef BusMode;
  26. QSPI_CmdFormatTypeDef CmdFormat;
  27. uint32_t Address;
  28. uint32_t WrData;
  29. uint32_t RdData;
  30. }FLASH_CommandTypeDef;
  31. #define QSPI_FIFO_NUM 32
  32. void __FUNC_IN_RAM__ CACHE_CleanAll(CACHE_TypeDef *Cache)
  33. {
  34. while (Cache->CACHE_CS & CACHE_IS_BUSY);
  35. Cache->CACHE_REF = CACHE_REFRESH_ALLTAG;
  36. Cache->CACHE_REF |= CACHE_REFRESH;
  37. while ((Cache->CACHE_REF & CACHE_REFRESH));
  38. }
  39. #define FLASH_QSPI_TIMEOUT_DEFAULT_CNT (19000) //18944
  40. #define FLASH_QSPI_ACCESS_REQ_ENABLE (0x00000001U)
  41. #define FLASH_QSPI_FLASH_READY_ENABLE (0x0000006BU)
  42. static int32_t __FUNC_IN_RAM__ prvQSPI_Command(FLASH_CommandTypeDef *cmd, int32_t timeout)
  43. {
  44. int32_t i;
  45. int32_t status = -ERROR_OPERATION_FAILED;
  46. QSPI->REG_WDATA = cmd->WrData;
  47. QSPI->ADDRES = (QSPI->ADDRES & ~QUADSPI_ADDRESS_ADR) | (cmd->Address << 8);
  48. QSPI->FCU_CMD = (QSPI->FCU_CMD & ~(QUADSPI_FCU_CMD_CODE | QUADSPI_FCU_CMD_BUS_MODE | QUADSPI_FCU_CMD_CMD_FORMAT | QUADSPI_FCU_CMD_ACCESS_REQ)) | ((cmd->Instruction << 24) |((uint32_t)( cmd->BusMode<< 8)) |((uint32_t)( cmd->CmdFormat << 4))| (FLASH_QSPI_ACCESS_REQ_ENABLE));
  49. //Wait For CMD done
  50. for (i = 0; i < timeout; i += 4)
  51. {
  52. if (QSPI->INT_RAWSTATUS & QUADSPI_INT_RAWSTATUS_DONE_IR)
  53. {
  54. QSPI->INT_CLEAR = QUADSPI_INT_CLEAR_DONE;
  55. status = ERROR_NONE;
  56. break;
  57. }
  58. }
  59. cmd->RdData = QSPI->REG_RDATA;
  60. return status;
  61. }
  62. static int32_t __FUNC_IN_RAM__ prvQSPI_WriteEnable(QSPI_BusModeTypeDef bus_mode)
  63. {
  64. FLASH_CommandTypeDef sCommand;
  65. sCommand.Instruction = SPIFLASH_CMD_WREN;
  66. sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8;
  67. if (QSPI_BUSMODE_444 == bus_mode)
  68. {
  69. sCommand.BusMode = QSPI_BUSMODE_444;
  70. }
  71. else
  72. {
  73. sCommand.BusMode = QSPI_BUSMODE_111;
  74. }
  75. if (prvQSPI_Command(&sCommand, FLASH_QSPI_TIMEOUT_DEFAULT_CNT))
  76. {
  77. return -ERROR_OPERATION_FAILED;
  78. }
  79. return ERROR_NONE;
  80. }
  81. //PP,QPP,Sector Erase,Block Erase, Chip Erase, Write Status Reg, Erase Security Reg
  82. static int32_t __FUNC_IN_RAM__ prvQSPI_IsBusy(QSPI_BusModeTypeDef bus_mode)
  83. {
  84. FLASH_CommandTypeDef sCommand;
  85. sCommand.Instruction = SPIFLASH_CMD_RDSR;
  86. sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_RREG8;
  87. if (QSPI_BUSMODE_444 == bus_mode)
  88. {
  89. sCommand.BusMode = QSPI_BUSMODE_444;
  90. }
  91. else
  92. {
  93. sCommand.BusMode = QSPI_BUSMODE_111;
  94. }
  95. if (prvQSPI_Command(&sCommand, FLASH_QSPI_TIMEOUT_DEFAULT_CNT))
  96. {
  97. return -ERROR_OPERATION_FAILED;
  98. }
  99. if (sCommand.RdData & BIT0)
  100. {
  101. return -ERROR_DEVICE_BUSY;
  102. }
  103. return ERROR_NONE;
  104. }
  105. int32_t __FUNC_IN_RAM__ Flash_Erase(uint32_t Address, uint32_t Length)
  106. {
  107. FLASH_CommandTypeDef sCommand;
  108. uint32_t TotalLen = 0;
  109. uint32_t FlashAddress, DummyLen;
  110. Address &= (uint32_t)(0x00FFFFFF);
  111. while (CACHE->CACHE_CS & CACHE_IS_BUSY);
  112. sCommand.BusMode = QSPI_BUSMODE_111;
  113. sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24;
  114. while (TotalLen < Length)
  115. {
  116. if (prvQSPI_WriteEnable(sCommand.BusMode) != 0)
  117. {
  118. return -ERROR_OPERATION_FAILED;
  119. }
  120. FlashAddress = Address + TotalLen;
  121. DummyLen = Length - TotalLen;
  122. if (!(FlashAddress & SPI_FLASH_BLOCK_MASK) && (DummyLen >= SPI_FLASH_BLOCK_SIZE))
  123. {
  124. sCommand.Instruction = SPIFLASH_CMD_BE;
  125. TotalLen += SPI_FLASH_BLOCK_SIZE;
  126. }
  127. else
  128. {
  129. sCommand.Instruction = SPIFLASH_CMD_SE;
  130. TotalLen += SPI_FLASH_SECTOR_SIZE;
  131. }
  132. sCommand.Address = FlashAddress;
  133. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  134. __disable_irq();
  135. #endif
  136. if (prvQSPI_Command(&sCommand, FLASH_QSPI_TIMEOUT_DEFAULT_CNT))
  137. {
  138. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  139. CACHE_CleanAll(CACHE);
  140. __enable_irq();
  141. #endif
  142. return -ERROR_OPERATION_FAILED;
  143. }
  144. while(prvQSPI_IsBusy(sCommand.BusMode));
  145. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  146. __enable_irq();
  147. #endif
  148. }
  149. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  150. CACHE_CleanAll(CACHE);
  151. #endif
  152. return ERROR_NONE;
  153. }
  154. int32_t __FUNC_IN_RAM__ Flash_Program(uint32_t Address, const uint8_t *pBuf, uint32_t Len)
  155. {
  156. FLASH_CommandTypeDef sCommand;
  157. uint32_t FinishLen = 0, DummyLen, ProgramLen, i;
  158. int32_t status;
  159. /* Initialize the adress variables */
  160. sCommand.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
  161. sCommand.BusMode = QSPI_BUSMODE_114;
  162. sCommand.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
  163. Address &= 0x00ffffff;
  164. while(FinishLen < Len)
  165. {
  166. if (prvQSPI_WriteEnable(QSPI_BUSMODE_111))
  167. {
  168. return -ERROR_OPERATION_FAILED;
  169. }
  170. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  171. __disable_irq();
  172. ProgramLen = ((Len - FinishLen) > 128)?128:(Len - FinishLen);
  173. #else
  174. ProgramLen = ((Len - FinishLen) > QSPI_FIFO_NUM)?QSPI_FIFO_NUM:(Len - FinishLen);
  175. #endif
  176. QSPI->FIFO_CNTL |= QUADSPI_FIFO_CNTL_TFFH;
  177. QSPI->BYTE_NUM = (ProgramLen << 16);
  178. sCommand.Address = Address + FinishLen;
  179. DummyLen = 0;
  180. while((DummyLen < ProgramLen) && !(QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_TFFL))
  181. {
  182. QSPI->WR_FIFO = pBuf[FinishLen + DummyLen] | (pBuf[FinishLen + DummyLen + 1] << 8) | (pBuf[FinishLen + DummyLen + 2] << 16) | (pBuf[FinishLen + DummyLen + 3] << 24);
  183. DummyLen += 4;
  184. }
  185. QSPI->ADDRES = (QSPI->ADDRES & ~QUADSPI_ADDRESS_ADR) | (sCommand.Address << 8);
  186. QSPI->FCU_CMD = (QSPI->FCU_CMD & ~(QUADSPI_FCU_CMD_CODE | QUADSPI_FCU_CMD_BUS_MODE | QUADSPI_FCU_CMD_CMD_FORMAT | QUADSPI_FCU_CMD_ACCESS_REQ)) | ((sCommand.Instruction << 24) |((uint32_t)( sCommand.BusMode<< 8)) |((uint32_t)( sCommand.CmdFormat << 4))| (FLASH_QSPI_ACCESS_REQ_ENABLE));
  187. while(DummyLen < ProgramLen)
  188. {
  189. while(QSPI->FIFO_CNTL & QUADSPI_FIFO_CNTL_TFFL)
  190. {
  191. }
  192. QSPI->WR_FIFO = pBuf[FinishLen + DummyLen] | (pBuf[FinishLen + DummyLen + 1] << 8) | (pBuf[FinishLen + DummyLen + 2] << 16) | (pBuf[FinishLen + DummyLen + 3] << 24);
  193. DummyLen += 4;
  194. }
  195. // DBG("%u", DummyLen);
  196. status = -ERROR_OPERATION_FAILED;
  197. for (i = 0; i < FLASH_QSPI_TIMEOUT_DEFAULT_CNT; i += 4)
  198. {
  199. if (QSPI->INT_RAWSTATUS & QUADSPI_INT_RAWSTATUS_DONE_IR)
  200. {
  201. QSPI->INT_CLEAR = QUADSPI_INT_CLEAR_DONE;
  202. status = ERROR_NONE;
  203. break;
  204. }
  205. }
  206. if (status)
  207. {
  208. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  209. CACHE_CleanAll(CACHE);
  210. __enable_irq();
  211. DBGF;
  212. #endif
  213. return status;
  214. }
  215. while (prvQSPI_IsBusy(QSPI_BUSMODE_111));
  216. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  217. __enable_irq();
  218. #endif
  219. FinishLen += ProgramLen;
  220. }
  221. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  222. CACHE_CleanAll(CACHE);
  223. #endif
  224. return ERROR_NONE;
  225. }
  226. /**
  227. * @brief Flash Erase Sector.
  228. * @param sectorAddress: The sector address to be erased
  229. * @retval FLASH Status: The returned value can be: QSPI_STATUS_ERROR, QSPI_STATUS_OK
  230. */
  231. uint8_t FLASH_EraseSector(uint32_t sectorAddress)
  232. {
  233. uint8_t ret;
  234. __disable_irq();
  235. //__disable_fault_irq();
  236. ret = ROM_QSPI_EraseSector(NULL, sectorAddress);
  237. //__enable_fault_irq();
  238. __enable_irq();
  239. return ret;
  240. }
  241. /**
  242. * @brief Flash Program Interface.
  243. * @param addr: specifies the address to be programmed.
  244. * @param size: specifies the size to be programmed.
  245. * @param buffer: pointer to the data to be programmed, need word aligned
  246. * @retval FLASH Status: The returned value can be: QSPI_STATUS_ERROR, QSPI_STATUS_OK
  247. */
  248. uint8_t FLASH_ProgramPage(uint32_t addr, uint32_t size, uint8_t *buffer)
  249. {
  250. uint8_t ret;
  251. QSPI_CommandTypeDef cmdType;
  252. cmdType.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
  253. cmdType.BusMode = QSPI_BUSMODE_114;
  254. cmdType.CmdFormat = QSPI_CMDFORMAT_CMD8_ADDR24_PDAT;
  255. __disable_irq();
  256. //__disable_fault_irq();
  257. ret = ROM_QSPI_ProgramPage(&cmdType, DMA_Channel_1, addr, size, buffer);
  258. //__enable_fault_irq();
  259. __enable_irq();
  260. return ret;
  261. }
  262. int Flash_EraseSector(uint32_t address, uint8_t NeedCheck)
  263. {
  264. uint8_t buf[__FLASH_PAGE_SIZE__];
  265. uint32_t i;
  266. uint8_t retry = 1;
  267. void *res;
  268. memset(buf, 0xff, __FLASH_PAGE_SIZE__);
  269. BL_ERASESECTOR_AGAIN:
  270. FLASH_EraseSector(address);
  271. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  272. CACHE_CleanAll(CACHE);
  273. #endif
  274. if (!NeedCheck) return ERROR_NONE;
  275. for(i = 0; i < 4096; i+=__FLASH_PAGE_SIZE__)
  276. {
  277. res = memcmp(address + i, buf, __FLASH_PAGE_SIZE__);
  278. if (res)
  279. {
  280. DBG_INFO("%x", res);
  281. if (retry)
  282. {
  283. retry = 0;
  284. goto BL_ERASESECTOR_AGAIN;
  285. }
  286. else
  287. {
  288. return -1;
  289. }
  290. }
  291. }
  292. return 0;
  293. }
  294. int Flash_ProgramData(uint32_t address, uint32_t *Data, uint32_t Len, uint8_t NeedCheck)
  295. {
  296. void *res;
  297. uint32_t size = (Len + (4 - 1)) & (~(4 - 1));
  298. FLASH_ProgramPage(address, size, Data);
  299. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  300. CACHE_CleanAll(CACHE);
  301. #endif
  302. if (!NeedCheck) return ERROR_NONE;
  303. res = memcmp(address, Data, Len);
  304. if (res)
  305. {
  306. DBG_INFO("%x", res);
  307. FLASH_ProgramPage(address, size, Data);
  308. #if (defined __BUILD_OS__) || (defined __BUILD_APP__)
  309. CACHE_CleanAll(CACHE);
  310. #endif
  311. res = memcmp(address, Data, size);
  312. if (res)
  313. {
  314. DBG_INFO("%x", res);
  315. return -1;
  316. }
  317. }
  318. return 0;
  319. }