mmu_psram_flash.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @Backgrounds
  8. *
  9. * This file contains 2 parts:
  10. * 1. Feature: Copy Flash content to PSRAM. Related APIs are private:
  11. * - mmu_config_psram_text_segment()
  12. * - mmu_config_psram_rodata_segment()
  13. *
  14. * 2. Private APIs used by `flash_mmap.c` and `cache_utils.c`
  15. * APIs in 2 are due to lack of MMU driver. There will be an MMU driver to maintain vaddr range.
  16. * APIs in 2 will be refactored when MMU driver is ready
  17. */
  18. #include <sys/param.h>
  19. #include "sdkconfig.h"
  20. #include "esp_log.h"
  21. #include "esp_attr.h"
  22. #include "soc/ext_mem_defs.h"
  23. #include "hal/cache_types.h"
  24. #include "hal/cache_ll.h"
  25. #include "esp_private/mmu_psram_flash.h"
  26. #if CONFIG_IDF_TARGET_ESP32S2
  27. #include "esp32s2/rom/cache.h"
  28. #elif CONFIG_IDF_TARGET_ESP32S3
  29. #include "esp32s3/rom/cache.h"
  30. #endif
  31. /*----------------------------------------------------------------------------
  32. Part 1 APIs (See @Backgrounds on top of this file)
  33. -------------------------------------------------------------------------------*/
  34. #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
  35. //page_size - 1, where page_size on s2 and s3 is always 0x10000. To be refactored by MMU driver
  36. #define INVALID_PHY_PAGE 0xffff
  37. const static char *TAG = "mmu_psram";
  38. //TODO IDF-4387
  39. static uint32_t page0_mapped = 0;
  40. static uint32_t page0_page = INVALID_PHY_PAGE;
  41. #endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
  42. #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
  43. esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
  44. {
  45. uint32_t page_id = start_page;
  46. uint32_t flash_pages = 0;
  47. #if CONFIG_IDF_TARGET_ESP32S2
  48. flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS0, &page0_mapped);
  49. flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS1, &page0_mapped);
  50. #elif CONFIG_IDF_TARGET_ESP32S3
  51. flash_pages += Cache_Count_Flash_Pages(CACHE_IBUS, &page0_mapped);
  52. #endif
  53. if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
  54. ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash instructions, need %d B, from %d B to %d B",
  55. MMU_PAGE_TO_BYTES(flash_pages), MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(flash_pages + page_id));
  56. return ESP_FAIL;
  57. }
  58. //Enable the most high bus, which is used for copying FLASH .text to PSRAM
  59. cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, SOC_EXTRAM_DATA_HIGH, 0);
  60. cache_ll_l1_enable_bus(0, bus_mask);
  61. #if !CONFIG_FREERTOS_UNICORE
  62. bus_mask = cache_ll_l1_get_bus(1, SOC_EXTRAM_DATA_HIGH, 0);
  63. cache_ll_l1_enable_bus(1, bus_mask);
  64. #endif
  65. instruction_flash_page_info_init(page_id);
  66. #if CONFIG_IDF_TARGET_ESP32S2
  67. page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS0, SOC_IRAM0_ADDRESS_LOW, page_id, &page0_page);
  68. page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS1, SOC_IRAM1_ADDRESS_LOW, page_id, &page0_page);
  69. #elif CONFIG_IDF_TARGET_ESP32S3
  70. page_id = Cache_Flash_To_SPIRAM_Copy(CACHE_IBUS, SOC_IRAM0_CACHE_ADDRESS_LOW, page_id, &page0_page);
  71. #endif
  72. ESP_EARLY_LOGV(TAG, "after copy instruction, page_id is %d", page_id);
  73. ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM");
  74. *out_page = page_id - start_page;
  75. return ESP_OK;
  76. }
  77. #endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
  78. #if CONFIG_SPIRAM_RODATA
  79. esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
  80. {
  81. uint32_t page_id = start_page;
  82. uint32_t flash_pages = 0;
  83. #if CONFIG_IDF_TARGET_ESP32S2
  84. flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS2, &page0_mapped);
  85. flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS0, &page0_mapped);
  86. flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS1, &page0_mapped);
  87. flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS2, &page0_mapped);
  88. #elif CONFIG_IDF_TARGET_ESP32S3
  89. flash_pages += Cache_Count_Flash_Pages(CACHE_DBUS, &page0_mapped);
  90. #endif
  91. if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
  92. ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the instructions, need to copy to %d B.", MMU_PAGE_TO_BYTES(flash_pages + page_id));
  93. return ESP_FAIL;
  94. }
  95. //Enable the most high bus, which is used for copying FLASH .text to PSRAM
  96. cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, SOC_EXTRAM_DATA_HIGH, 0);
  97. cache_ll_l1_enable_bus(0, bus_mask);
  98. #if !CONFIG_FREERTOS_UNICORE
  99. bus_mask = cache_ll_l1_get_bus(1, SOC_EXTRAM_DATA_HIGH, 0);
  100. cache_ll_l1_enable_bus(1, bus_mask);
  101. #endif
  102. rodata_flash_page_info_init(page_id);
  103. #if CONFIG_IDF_TARGET_ESP32S2
  104. page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS2, SOC_DROM0_ADDRESS_LOW, page_id, &page0_page);
  105. page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS0, SOC_DRAM0_ADDRESS_LOW, page_id, &page0_page);
  106. page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS1, SOC_DRAM1_ADDRESS_LOW, page_id, &page0_page);
  107. page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS2, SOC_DPORT_ADDRESS_LOW, page_id, &page0_page);
  108. #elif CONFIG_IDF_TARGET_ESP32S3
  109. page_id = Cache_Flash_To_SPIRAM_Copy(CACHE_DBUS, SOC_DRAM0_CACHE_ADDRESS_LOW, page_id, &page0_page);
  110. #endif
  111. ESP_EARLY_LOGV(TAG, "after copy rodata, page_id is %d", page_id);
  112. ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM");
  113. *out_page = page_id - start_page;
  114. return ESP_OK;
  115. }
  116. #endif //#if CONFIG_SPIRAM_RODATA
  117. /*----------------------------------------------------------------------------
  118. Part 2 APIs (See @Backgrounds on top of this file)
  119. -------------------------------------------------------------------------------*/
  120. extern int _instruction_reserved_start;
  121. extern int _instruction_reserved_end;
  122. extern int _rodata_reserved_start;
  123. extern int _rodata_reserved_end;
  124. //------------------------------------Copy Flash .text to PSRAM-------------------------------------//
  125. #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
  126. static uint32_t instruction_in_spiram;
  127. static uint32_t instr_start_page;
  128. static uint32_t instr_end_page;
  129. static int instr_flash2spiram_offs;
  130. /**
  131. * - These logics are abstracted from the PSRAM driver
  132. * - These functions are only required by `flash_mmap.c` for converting paddr to vaddr, and vice versa
  133. * - The `flash_mmpa.c` will be rewritten into MMU driver
  134. *
  135. * Therefore, keep the APIs here for now
  136. */
  137. void instruction_flash_page_info_init(uint32_t psram_start_physical_page)
  138. {
  139. #if CONFIG_IDF_TARGET_ESP32S2
  140. uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
  141. uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & SOC_MMU_VADDR_MASK) / MMU_PAGE_SIZE;
  142. instr_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START))[instr_mmu_offset];
  143. #elif CONFIG_IDF_TARGET_ESP32S3
  144. uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - SOC_IROM_LOW + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
  145. instr_start_page = *((volatile uint32_t *)(DR_REG_MMU_TABLE + CACHE_IROM_MMU_START));
  146. #endif
  147. instr_start_page &= SOC_MMU_VALID_VAL_MASK;
  148. instr_end_page = instr_start_page + instr_page_cnt - 1;
  149. instr_flash2spiram_offs = instr_start_page - psram_start_physical_page;
  150. instruction_in_spiram = 1;
  151. ESP_DRAM_LOGV("mmu_psram", "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", instr_start_page, psram_start_physical_page, instr_flash2spiram_offs);
  152. }
  153. uint32_t esp_spiram_instruction_access_enabled(void)
  154. {
  155. return instruction_in_spiram;
  156. }
  157. int instruction_flash2spiram_offset(void)
  158. {
  159. return instr_flash2spiram_offs;
  160. }
  161. uint32_t instruction_flash_start_page_get(void)
  162. {
  163. return instr_start_page;
  164. }
  165. uint32_t instruction_flash_end_page_get(void)
  166. {
  167. return instr_end_page;
  168. }
  169. #endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS
  170. #if CONFIG_SPIRAM_RODATA
  171. //------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
  172. static uint32_t rodata_in_spiram;
  173. static int rodata_flash2spiram_offs;
  174. static uint32_t rodata_start_page;
  175. static uint32_t rodata_end_page;
  176. /**
  177. * - These logics are abstracted from the PSRAM driver
  178. * - These functions are only required by `flash_mmap.c` for converting paddr to vaddr, and vice versa
  179. * - The `flash_mmpa.c` will be rewritten into MMU driver
  180. *
  181. * Therefore, keep the APIs here for now
  182. */
  183. void rodata_flash_page_info_init(uint32_t psram_start_physical_page)
  184. {
  185. #if CONFIG_IDF_TARGET_ESP32S2
  186. uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
  187. uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & SOC_MMU_VADDR_MASK) / MMU_PAGE_SIZE;
  188. rodata_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START))[rodata_mmu_offset];
  189. #elif CONFIG_IDF_TARGET_ESP32S3
  190. uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - ((uint32_t)&_rodata_reserved_start & ~(MMU_PAGE_SIZE - 1)) + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
  191. rodata_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + CACHE_DROM_MMU_START);
  192. #endif
  193. rodata_start_page &= SOC_MMU_VALID_VAL_MASK;
  194. rodata_end_page = rodata_start_page + rodata_page_cnt - 1;
  195. rodata_flash2spiram_offs = rodata_start_page - psram_start_physical_page;
  196. rodata_in_spiram = 1;
  197. ESP_DRAM_LOGV("mmu_psram", "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", rodata_start_page, psram_start_physical_page, rodata_flash2spiram_offs);
  198. }
  199. uint32_t esp_spiram_rodata_access_enabled(void)
  200. {
  201. return rodata_in_spiram;
  202. }
  203. int rodata_flash2spiram_offset(void)
  204. {
  205. return rodata_flash2spiram_offs;
  206. }
  207. uint32_t rodata_flash_start_page_get(void)
  208. {
  209. return rodata_start_page;
  210. }
  211. uint32_t rodata_flash_end_page_get(void)
  212. {
  213. return rodata_end_page;
  214. }
  215. #endif //#if CONFIG_SPIRAM_RODATA