fal_flash_port.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Copyright (c) 2022-2023 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-03-09 hpmicro First implementation
  9. * 2022-08-01 hpmicro Fixed random crashing during kvdb_init
  10. * 2022-08-03 hpmicro Improved erase speed
  11. * 2023-01-31 hpmicro Fix random crashing issue if the global interrupt is always enabled
  12. *
  13. */
  14. #include <rtthread.h>
  15. #include <rthw.h>
  16. #ifdef RT_USING_FAL
  17. #include "fal.h"
  18. #include "hpm_romapi.h"
  19. #include "board.h"
  20. #include "hpm_l1c_drv.h"
  21. #define FAL_ENTER_CRITICAL() do {\
  22. disable_global_irq(CSR_MSTATUS_MIE_MASK);\
  23. }while(0)
  24. #define FAL_EXIT_CRITICAL() do {\
  25. enable_global_irq(CSR_MSTATUS_MIE_MASK);\
  26. }while(0)
  27. #define FAL_RAMFUNC __attribute__((section(".isr_vector")))
  28. /***************************************************************************************************
  29. * FAL Porting Guide
  30. *
  31. * 1. Most FLASH devices do not support RWW (Read-while-Write), the codes to access the FLASH
  32. * must be placed at RAM or ROM code
  33. * 2. During FLASH erase/program, it is recommended to disable the interrupt, or place the
  34. * interrupt related codes to RAM
  35. *
  36. ***************************************************************************************************/
  37. static int init(void);
  38. static int read(long offset, rt_uint8_t *buf, rt_size_t size);
  39. static int write(long offset, const rt_uint8_t *buf, rt_size_t size);
  40. static int erase(long offset, rt_size_t size);
  41. static xpi_nor_config_t s_flashcfg;
  42. /**
  43. * @brief FAL Flash device context
  44. */
  45. struct fal_flash_dev nor_flash0 =
  46. {
  47. .name = NOR_FLASH_DEV_NAME,
  48. /* If porting this code to the device with FLASH connected to XPI1, the address must be changed to 0x90000000 */
  49. .addr = NOR_FLASH_MEM_BASE,
  50. .len = 8 * 1024 * 1024,
  51. .blk_size = 4096,
  52. .ops = { .init = init, .read = read, .write = write, .erase = erase },
  53. .write_gran = 1
  54. };
  55. /**
  56. * @brief FAL initialization
  57. * This function probes the FLASH using the ROM API
  58. */
  59. FAL_RAMFUNC static int init(void)
  60. {
  61. int ret = RT_EOK;
  62. xpi_nor_config_option_t cfg_option;
  63. cfg_option.header.U = BOARD_APP_XPI_NOR_CFG_OPT_HDR;
  64. cfg_option.option0.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT0;
  65. cfg_option.option1.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT1;
  66. FAL_ENTER_CRITICAL();
  67. hpm_stat_t status = rom_xpi_nor_auto_config(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, &cfg_option);
  68. FAL_EXIT_CRITICAL();
  69. if (status != status_success)
  70. {
  71. ret = -RT_ERROR;
  72. }
  73. else
  74. {
  75. s_flashcfg.device_info.clk_freq_for_non_read_cmd = 0U;
  76. /* update the flash chip information */
  77. rt_uint32_t sector_size;
  78. rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_sector_size, &sector_size);
  79. rt_uint32_t flash_size;
  80. rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_total_size, &flash_size);
  81. nor_flash0.blk_size = sector_size;
  82. nor_flash0.len = flash_size;
  83. }
  84. return ret;
  85. }
  86. /**
  87. * @brief FAL read function
  88. * Read data from FLASH
  89. * @param offset FLASH offset
  90. * @param buf Buffer to hold data read by this API
  91. * @param size Size of data to be read
  92. * @return actual read bytes
  93. */
  94. FAL_RAMFUNC static int read(long offset, rt_uint8_t *buf, rt_size_t size)
  95. {
  96. rt_uint32_t flash_addr = nor_flash0.addr + offset;
  97. rt_uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(flash_addr);
  98. rt_uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(flash_addr + size);
  99. rt_uint32_t aligned_size = aligned_end - aligned_start;
  100. rt_base_t level = rt_hw_interrupt_disable();
  101. l1c_dc_invalidate(aligned_start, aligned_size);
  102. rt_hw_interrupt_enable(level);
  103. (void) rt_memcpy(buf, (void*) flash_addr, size);
  104. return size;
  105. }
  106. /**
  107. * @brief Write unaligned data to the page
  108. * @param offset FLASH offset
  109. * @param buf Data buffer
  110. * @param size Size of data to be written
  111. * @return actual size of written data or error code
  112. */
  113. FAL_RAMFUNC static int write_unaligned_page_data(long offset, const rt_uint32_t *buf, rt_size_t size)
  114. {
  115. hpm_stat_t status;
  116. FAL_ENTER_CRITICAL();
  117. status = rom_xpi_nor_program(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, buf, offset, size);
  118. FAL_EXIT_CRITICAL();
  119. if (status != status_success)
  120. {
  121. return -RT_ERROR;
  122. rt_kprintf("write failed, status=%d\n", status);
  123. }
  124. return size;
  125. }
  126. /**
  127. * @brief FAL write function
  128. * Write data to specified FLASH address
  129. * @param offset FLASH offset
  130. * @param buf Data buffer
  131. * @param size Size of data to be written
  132. * @return actual size of written data or error code
  133. */
  134. FAL_RAMFUNC static int write(long offset, const rt_uint8_t *buf, rt_size_t size)
  135. {
  136. rt_uint32_t *src = NULL;
  137. rt_uint32_t buf_32[64];
  138. rt_uint32_t write_size;
  139. rt_size_t remaining_size = size;
  140. int ret = (int)size;
  141. rt_uint32_t page_size;
  142. rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_page_size, &page_size);
  143. rt_uint32_t offset_in_page = offset % page_size;
  144. if (offset_in_page != 0)
  145. {
  146. rt_uint32_t write_size_in_page = page_size - offset_in_page;
  147. rt_uint32_t write_page_size = MIN(write_size_in_page, size);
  148. (void) rt_memcpy(buf_32, buf, write_page_size);
  149. write_size = write_unaligned_page_data(offset, buf_32, write_page_size);
  150. if (write_size < 0)
  151. {
  152. ret = -RT_ERROR;
  153. goto write_quit;
  154. }
  155. remaining_size -= write_page_size;
  156. offset += write_page_size;
  157. buf += write_page_size;
  158. }
  159. while (remaining_size > 0)
  160. {
  161. write_size = MIN(remaining_size, sizeof(buf_32));
  162. rt_memcpy(buf_32, buf, write_size);
  163. src = &buf_32[0];
  164. FAL_ENTER_CRITICAL();
  165. hpm_stat_t status = rom_xpi_nor_program(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, src,
  166. offset, write_size);
  167. FAL_EXIT_CRITICAL();
  168. if (status != status_success)
  169. {
  170. ret = -RT_ERROR;
  171. rt_kprintf("write failed, status=%d\n", status);
  172. break;
  173. }
  174. remaining_size -= write_size;
  175. buf += write_size;
  176. offset += write_size;
  177. }
  178. write_quit:
  179. return ret;
  180. }
  181. /**
  182. * @brief FAL erase function
  183. * Erase specified FLASH region
  184. * @param offset the start FLASH address to be erased
  185. * @param size size of the region to be erased
  186. * @ret RT_EOK Erase operation is successful
  187. * @retval -RT_ERROR Erase operation failed
  188. */
  189. FAL_RAMFUNC static int erase(long offset, rt_size_t size)
  190. {
  191. rt_uint32_t aligned_size = (size + nor_flash0.blk_size - 1U) & ~(nor_flash0.blk_size - 1U);
  192. hpm_stat_t status;
  193. int ret = (int)size;
  194. rt_uint32_t block_size;
  195. rt_uint32_t sector_size;
  196. (void) rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_sector_size, &sector_size);
  197. (void) rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_block_size, &block_size);
  198. rt_uint32_t erase_unit;
  199. while (aligned_size > 0)
  200. {
  201. FAL_ENTER_CRITICAL();
  202. if ((offset % block_size == 0) && (aligned_size >= block_size))
  203. {
  204. erase_unit = block_size;
  205. status = rom_xpi_nor_erase_block(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, offset);
  206. }
  207. else
  208. {
  209. erase_unit = sector_size;
  210. status = rom_xpi_nor_erase_sector(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, offset);
  211. }
  212. FAL_EXIT_CRITICAL();
  213. if (status != status_success)
  214. {
  215. ret = -RT_ERROR;
  216. break;
  217. }
  218. offset += erase_unit;
  219. aligned_size -= erase_unit;
  220. }
  221. return ret;
  222. }
  223. #endif /* RT_USING_FAL */