furi_hal_flash.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #include <furi_hal_flash.h>
  2. #include <furi_hal_bt.h>
  3. #include <furi.h>
  4. #include <ble.h>
  5. #include <shci.h>
  6. #include <stm32wbxx.h>
  7. #define FURI_HAL_TAG "FuriHalFlash"
  8. #define FURI_HAL_CRITICAL_MSG "Critical flash operation fail"
  9. #define FURI_HAL_FLASH_READ_BLOCK 8
  10. #define FURI_HAL_FLASH_WRITE_BLOCK 8
  11. #define FURI_HAL_FLASH_PAGE_SIZE 4096
  12. #define FURI_HAL_FLASH_CYCLES_COUNT 10000
  13. #define FURI_HAL_FLASH_TIMEOUT 1000
  14. #define FURI_HAL_FLASH_KEY1 0x45670123U
  15. #define FURI_HAL_FLASH_KEY2 0xCDEF89ABU
  16. #define FURI_HAL_FLASH_TOTAL_PAGES 256
  17. #define FURI_HAL_FLASH_SR_ERRORS \
  18. (FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_SIZERR | \
  19. FLASH_SR_PGSERR | FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR | FLASH_SR_OPTVERR)
  20. #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL))
  21. #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
  22. (((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \
  23. (((__VALUE__) % 8UL) == 0UL))
  24. /* Free flash space borders, exported by linker */
  25. extern const void __free_flash_start__;
  26. size_t furi_hal_flash_get_base() {
  27. return FLASH_BASE;
  28. }
  29. size_t furi_hal_flash_get_read_block_size() {
  30. return FURI_HAL_FLASH_READ_BLOCK;
  31. }
  32. size_t furi_hal_flash_get_write_block_size() {
  33. return FURI_HAL_FLASH_WRITE_BLOCK;
  34. }
  35. size_t furi_hal_flash_get_page_size() {
  36. return FURI_HAL_FLASH_PAGE_SIZE;
  37. }
  38. size_t furi_hal_flash_get_cycles_count() {
  39. return FURI_HAL_FLASH_CYCLES_COUNT;
  40. }
  41. const void* furi_hal_flash_get_free_start_address() {
  42. return &__free_flash_start__;
  43. }
  44. const void* furi_hal_flash_get_free_end_address() {
  45. uint32_t sfr_reg_val = READ_REG(FLASH->SFR);
  46. uint32_t sfsa = (READ_BIT(sfr_reg_val, FLASH_SFR_SFSA) >> FLASH_SFR_SFSA_Pos);
  47. return (const void*)((sfsa * FURI_HAL_FLASH_PAGE_SIZE) + FLASH_BASE);
  48. }
  49. size_t furi_hal_flash_get_free_page_start_address() {
  50. size_t start = (size_t)furi_hal_flash_get_free_start_address();
  51. size_t page_start = start - start % FURI_HAL_FLASH_PAGE_SIZE;
  52. if(page_start != start) {
  53. page_start += FURI_HAL_FLASH_PAGE_SIZE;
  54. }
  55. return page_start;
  56. }
  57. size_t furi_hal_flash_get_free_page_count() {
  58. size_t end = (size_t)furi_hal_flash_get_free_end_address();
  59. size_t page_start = (size_t)furi_hal_flash_get_free_page_start_address();
  60. return (end - page_start) / FURI_HAL_FLASH_PAGE_SIZE;
  61. }
  62. void furi_hal_flash_init() {
  63. // Errata 2.2.9, Flash OPTVERR flag is always set after system reset
  64. WRITE_REG(FLASH->SR, FLASH_SR_OPTVERR);
  65. //__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
  66. }
  67. static void furi_hal_flash_unlock() {
  68. /* verify Flash is locked */
  69. furi_check(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0U);
  70. /* Authorize the FLASH Registers access */
  71. WRITE_REG(FLASH->KEYR, FURI_HAL_FLASH_KEY1);
  72. WRITE_REG(FLASH->KEYR, FURI_HAL_FLASH_KEY2);
  73. /* verify Flash is unlock */
  74. furi_check(READ_BIT(FLASH->CR, FLASH_CR_LOCK) == 0U);
  75. }
  76. static void furi_hal_flash_lock(void) {
  77. /* verify Flash is unlocked */
  78. furi_check(READ_BIT(FLASH->CR, FLASH_CR_LOCK) == 0U);
  79. /* Set the LOCK Bit to lock the FLASH Registers access */
  80. /* @Note The lock and unlock procedure is done only using CR registers even from CPU2 */
  81. SET_BIT(FLASH->CR, FLASH_CR_LOCK);
  82. /* verify Flash is locked */
  83. furi_check(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0U);
  84. }
  85. static void furi_hal_flash_begin_with_core2(bool erase_flag) {
  86. // Take flash controller ownership
  87. while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) {
  88. osThreadYield();
  89. }
  90. // Unlock flash operation
  91. furi_hal_flash_unlock();
  92. // Erase activity notification
  93. if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
  94. // 64mHz 5us core2 flag protection
  95. for(volatile uint32_t i = 0; i < 35; i++)
  96. ;
  97. while(true) {
  98. // Wait till flash controller become usable
  99. while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
  100. osThreadYield();
  101. };
  102. // Just a little more love
  103. taskENTER_CRITICAL();
  104. // Actually we already have mutex for it, but specification is specification
  105. if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) {
  106. taskEXIT_CRITICAL();
  107. osThreadYield();
  108. continue;
  109. }
  110. // Take sempahopre and prevent core2 from anything funky
  111. if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) {
  112. taskEXIT_CRITICAL();
  113. osThreadYield();
  114. continue;
  115. }
  116. break;
  117. }
  118. }
  119. static void furi_hal_flash_begin(bool erase_flag) {
  120. // Acquire dangerous ops mutex
  121. furi_hal_bt_lock_core2();
  122. // If Core2 is running use IPC locking
  123. if(furi_hal_bt_is_alive()) {
  124. furi_hal_flash_begin_with_core2(erase_flag);
  125. } else {
  126. furi_hal_flash_unlock();
  127. }
  128. }
  129. static void furi_hal_flash_end_with_core2(bool erase_flag) {
  130. // Funky ops are ok at this point
  131. LL_HSEM_ReleaseLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, 0);
  132. // Task switching is ok
  133. taskEXIT_CRITICAL();
  134. // Doesn't make much sense, does it?
  135. while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) {
  136. osThreadYield();
  137. }
  138. // Erase activity over, core2 can continue
  139. if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
  140. // Lock flash controller
  141. furi_hal_flash_lock();
  142. // Release flash controller ownership
  143. LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0);
  144. }
  145. static void furi_hal_flash_end(bool erase_flag) {
  146. // If Core2 is running use IPC locking
  147. if(furi_hal_bt_is_alive()) {
  148. furi_hal_flash_end_with_core2(erase_flag);
  149. } else {
  150. furi_hal_flash_lock();
  151. }
  152. // Release dangerous ops mutex
  153. furi_hal_bt_unlock_core2();
  154. }
  155. static void furi_hal_flush_cache(void) {
  156. /* Flush instruction cache */
  157. if(READ_BIT(FLASH->ACR, FLASH_ACR_ICEN) == FLASH_ACR_ICEN) {
  158. /* Disable instruction cache */
  159. LL_FLASH_DisableInstCache();
  160. /* Reset instruction cache */
  161. LL_FLASH_EnableInstCacheReset();
  162. LL_FLASH_DisableInstCacheReset();
  163. /* Enable instruction cache */
  164. LL_FLASH_EnableInstCache();
  165. }
  166. /* Flush data cache */
  167. if(READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) == FLASH_ACR_DCEN) {
  168. /* Disable data cache */
  169. LL_FLASH_DisableDataCache();
  170. /* Reset data cache */
  171. LL_FLASH_EnableDataCacheReset();
  172. LL_FLASH_DisableDataCacheReset();
  173. /* Enable data cache */
  174. LL_FLASH_EnableDataCache();
  175. }
  176. }
  177. bool furi_hal_flash_wait_last_operation(uint32_t timeout) {
  178. uint32_t error = 0;
  179. uint32_t countdown = 0;
  180. // Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
  181. // Even if the FLASH operation fails, the BUSY flag will be reset and an error
  182. // flag will be set
  183. countdown = timeout;
  184. while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) {
  185. if(LL_SYSTICK_IsActiveCounterFlag()) {
  186. countdown--;
  187. }
  188. if(countdown == 0) {
  189. return false;
  190. }
  191. }
  192. /* Check FLASH operation error flags */
  193. error = FLASH->SR;
  194. /* Check FLASH End of Operation flag */
  195. if((error & FLASH_SR_EOP) != 0U) {
  196. /* Clear FLASH End of Operation pending bit */
  197. CLEAR_BIT(FLASH->SR, FLASH_SR_EOP);
  198. }
  199. /* Now update error variable to only error value */
  200. error &= FURI_HAL_FLASH_SR_ERRORS;
  201. furi_check(error == 0);
  202. /* clear error flags */
  203. CLEAR_BIT(FLASH->SR, error);
  204. /* Wait for control register to be written */
  205. countdown = timeout;
  206. while(READ_BIT(FLASH->SR, FLASH_SR_CFGBSY)) {
  207. if(LL_SYSTICK_IsActiveCounterFlag()) {
  208. countdown--;
  209. }
  210. if(countdown == 0) {
  211. return false;
  212. }
  213. }
  214. return true;
  215. }
  216. bool furi_hal_flash_erase(uint8_t page) {
  217. furi_hal_flash_begin(true);
  218. // Ensure that controller state is valid
  219. furi_check(FLASH->SR == 0);
  220. /* Verify that next operation can be proceed */
  221. furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
  222. /* Select page and start operation */
  223. MODIFY_REG(
  224. FLASH->CR, FLASH_CR_PNB, ((page << FLASH_CR_PNB_Pos) | FLASH_CR_PER | FLASH_CR_STRT));
  225. /* Wait for last operation to be completed */
  226. furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
  227. /* If operation is completed or interrupted, disable the Page Erase Bit */
  228. CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
  229. /* Flush the caches to be sure of the data consistency */
  230. furi_hal_flush_cache();
  231. furi_hal_flash_end(true);
  232. return true;
  233. }
  234. static inline bool furi_hal_flash_write_dword_internal(size_t address, uint64_t* data) {
  235. /* Program first word */
  236. *(uint32_t*)address = (uint32_t)*data;
  237. // Barrier to ensure programming is performed in 2 steps, in right order
  238. // (independently of compiler optimization behavior)
  239. __ISB();
  240. /* Program second word */
  241. *(uint32_t*)(address + 4U) = (uint32_t)(*data >> 32U);
  242. /* Wait for last operation to be completed */
  243. furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
  244. return true;
  245. }
  246. bool furi_hal_flash_write_dword(size_t address, uint64_t data) {
  247. furi_hal_flash_begin(false);
  248. // Ensure that controller state is valid
  249. furi_check(FLASH->SR == 0);
  250. /* Check the parameters */
  251. furi_check(IS_ADDR_ALIGNED_64BITS(address));
  252. furi_check(IS_FLASH_PROGRAM_ADDRESS(address));
  253. /* Set PG bit */
  254. SET_BIT(FLASH->CR, FLASH_CR_PG);
  255. /* Do the thing */
  256. furi_check(furi_hal_flash_write_dword_internal(address, &data));
  257. /* If the program operation is completed, disable the PG or FSTPG Bit */
  258. CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
  259. furi_hal_flash_end(false);
  260. /* Wait for last operation to be completed */
  261. furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
  262. return true;
  263. }
  264. static size_t furi_hal_flash_get_page_address(uint8_t page) {
  265. return furi_hal_flash_get_base() + page * FURI_HAL_FLASH_PAGE_SIZE;
  266. }
  267. bool furi_hal_flash_program_page(const uint8_t page, const uint8_t* data, uint16_t _length) {
  268. uint16_t length = _length;
  269. furi_check(length <= FURI_HAL_FLASH_PAGE_SIZE);
  270. furi_hal_flash_erase(page);
  271. furi_hal_flash_begin(false);
  272. // Ensure that controller state is valid
  273. furi_check(FLASH->SR == 0);
  274. size_t page_start_address = furi_hal_flash_get_page_address(page);
  275. /* Set PG bit */
  276. SET_BIT(FLASH->CR, FLASH_CR_PG);
  277. size_t i_dwords = 0;
  278. for(i_dwords = 0; i_dwords < (length / 8); ++i_dwords) {
  279. /* Do the thing */
  280. size_t data_offset = i_dwords * 8;
  281. furi_check(furi_hal_flash_write_dword_internal(
  282. page_start_address + data_offset, (uint64_t*)&data[data_offset]));
  283. }
  284. if((length % 8) != 0) {
  285. /* there are more bytes, not fitting into dwords */
  286. uint64_t tail_data = 0;
  287. size_t data_offset = i_dwords * 8;
  288. for(int32_t tail_i = 0; tail_i < (length % 8); ++tail_i) {
  289. tail_data |= (((uint64_t)data[data_offset + tail_i]) << (tail_i * 8));
  290. }
  291. furi_check(
  292. furi_hal_flash_write_dword_internal(page_start_address + data_offset, &tail_data));
  293. }
  294. /* If the program operation is completed, disable the PG or FSTPG Bit */
  295. CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
  296. furi_hal_flash_end(false);
  297. return true;
  298. }
  299. int16_t furi_hal_flash_get_page_number(size_t address) {
  300. const size_t flash_base = furi_hal_flash_get_base();
  301. if((address < flash_base) ||
  302. (address > flash_base + FURI_HAL_FLASH_TOTAL_PAGES * FURI_HAL_FLASH_PAGE_SIZE)) {
  303. return -1;
  304. }
  305. return (address - flash_base) / FURI_HAL_FLASH_PAGE_SIZE;
  306. }