spiram.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
  3. we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
  4. */
  5. // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
  6. //
  7. // Licensed under the Apache License, Version 2.0 (the "License");
  8. // you may not use this file except in compliance with the License.
  9. // You may obtain a copy of the License at
  10. //
  11. // http://www.apache.org/licenses/LICENSE-2.0
  12. //
  13. // Unless required by applicable law or agreed to in writing, software
  14. // distributed under the License is distributed on an "AS IS" BASIS,
  15. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. // See the License for the specific language governing permissions and
  17. // limitations under the License.
  18. #include <stdint.h>
  19. #include <string.h>
  20. #include <sys/param.h>
  21. #include "sdkconfig.h"
  22. #include "esp_attr.h"
  23. #include "esp_err.h"
  24. #include "esp32/spiram.h"
  25. #include "spiram_psram.h"
  26. #include "esp_log.h"
  27. #include "freertos/FreeRTOS.h"
  28. #include "freertos/xtensa_api.h"
  29. #include "soc/soc.h"
  30. #include "esp_heap_caps_init.h"
  31. #include "soc/soc_memory_layout.h"
  32. #include "soc/dport_reg.h"
  33. #include "esp32/himem.h"
  34. #include "esp32/rom/cache.h"
  35. #if CONFIG_FREERTOS_UNICORE
  36. #define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
  37. #else
  38. #if CONFIG_MEMMAP_SPIRAM_CACHE_EVENODD
  39. #define PSRAM_MODE PSRAM_VADDR_MODE_EVENODD
  40. #else
  41. #define PSRAM_MODE PSRAM_VADDR_MODE_LOWHIGH
  42. #endif
  43. #endif
  44. #if CONFIG_SPIRAM
  45. static const char* TAG = "spiram";
  46. #if CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_40M
  47. #define PSRAM_SPEED PSRAM_CACHE_F40M_S40M
  48. #elif CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
  49. #define PSRAM_SPEED PSRAM_CACHE_F80M_S40M
  50. #elif CONFIG_SPIRAM_SPEED_80M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
  51. #define PSRAM_SPEED PSRAM_CACHE_F80M_S80M
  52. #else
  53. #error "FLASH speed can only be equal to or higher than SRAM speed while SRAM is enabled!"
  54. #endif
  55. #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
  56. extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end;
  57. #endif
  58. static bool spiram_inited=false;
  59. //If no function in esp_himem.c is used, this function will be linked into the
  60. //binary instead of the one in esp_himem.c, automatically making sure no memory
  61. //is reserved if no himem function is used.
  62. size_t __attribute__((weak)) esp_himem_reserved_area_size(void) {
  63. return 0;
  64. }
  65. static int spiram_size_usable_for_malloc(void)
  66. {
  67. int s=esp_spiram_get_size();
  68. if (s>4*1024*1024) s=4*1024*1024; //we can map at most 4MiB
  69. return s-esp_himem_reserved_area_size();
  70. }
  71. /*
  72. Simple RAM test. Writes a word every 32 bytes. Takes about a second to complete for 4MiB. Returns
  73. true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
  74. initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
  75. */
  76. bool esp_spiram_test(void)
  77. {
  78. volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
  79. size_t p;
  80. size_t s=spiram_size_usable_for_malloc();
  81. int errct=0;
  82. int initial_err=-1;
  83. for (p=0; p<(s/sizeof(int)); p+=8) {
  84. spiram[p]=p^0xAAAAAAAA;
  85. }
  86. for (p=0; p<(s/sizeof(int)); p+=8) {
  87. if (spiram[p]!=(p^0xAAAAAAAA)) {
  88. errct++;
  89. if (errct==1) initial_err=p*4;
  90. }
  91. }
  92. if (errct) {
  93. ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s/32, initial_err+SOC_EXTRAM_DATA_LOW);
  94. return false;
  95. } else {
  96. ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
  97. return true;
  98. }
  99. }
  100. void IRAM_ATTR esp_spiram_init_cache(void)
  101. {
  102. int size = esp_spiram_get_size();
  103. if (size > 4 * 1024 * 1024) size = 4 * 1024 * 1024; // we can map at most 4MByte
  104. //Enable external RAM in MMU
  105. cache_sram_mmu_set(0, 0, SOC_EXTRAM_DATA_LOW, 0, 32, (size / 1024 / 32));
  106. //Flush and enable icache for APP CPU
  107. #if !CONFIG_FREERTOS_UNICORE
  108. DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1);
  109. cache_sram_mmu_set(1, 0, SOC_EXTRAM_DATA_LOW, 0, 32, (size / 1024 / 32));
  110. #endif
  111. }
  112. esp_spiram_size_t esp_spiram_get_chip_size(void)
  113. {
  114. if (!spiram_inited) {
  115. ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
  116. abort();
  117. }
  118. psram_size_t psram_size = psram_get_size();
  119. switch (psram_size) {
  120. case PSRAM_SIZE_16MBITS:
  121. return ESP_SPIRAM_SIZE_16MBITS;
  122. case PSRAM_SIZE_32MBITS:
  123. return ESP_SPIRAM_SIZE_32MBITS;
  124. case PSRAM_SIZE_64MBITS:
  125. return ESP_SPIRAM_SIZE_64MBITS;
  126. default:
  127. return ESP_SPIRAM_SIZE_INVALID;
  128. }
  129. }
  130. esp_err_t esp_spiram_init(void)
  131. {
  132. esp_err_t r;
  133. r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
  134. if (r != ESP_OK) {
  135. #if CONFIG_SPIRAM_IGNORE_NOTFOUND
  136. ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
  137. #endif
  138. return r;
  139. }
  140. spiram_inited=true; //note: this needs to be set before esp_spiram_get_chip_*/esp_spiram_get_size calls
  141. #if (CONFIG_SPIRAM_SIZE != -1)
  142. if (esp_spiram_get_size()!=CONFIG_SPIRAM_SIZE) {
  143. ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE/1024, esp_spiram_get_size()/1024);
  144. return ESP_ERR_INVALID_SIZE;
  145. }
  146. #endif
  147. ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
  148. (esp_spiram_get_size()*8)/(1024*1024));
  149. ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_F40M_S40M ? "flash 40m sram 40m" : \
  150. PSRAM_SPEED == PSRAM_CACHE_F80M_S40M ? "flash 80m sram 40m" : \
  151. PSRAM_SPEED == PSRAM_CACHE_F80M_S80M ? "flash 80m sram 80m" : "ERROR");
  152. ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in %s mode.", \
  153. (PSRAM_MODE==PSRAM_VADDR_MODE_EVENODD)?"even/odd (2-core)": \
  154. (PSRAM_MODE==PSRAM_VADDR_MODE_LOWHIGH)?"low/high (2-core)": \
  155. (PSRAM_MODE==PSRAM_VADDR_MODE_NORMAL)?"normal (1-core)":"ERROR");
  156. return ESP_OK;
  157. }
  158. esp_err_t esp_spiram_add_to_heapalloc(void)
  159. {
  160. //Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory, so there's
  161. //no need to explicitly specify them.
  162. #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
  163. ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (spiram_size_usable_for_malloc() - (&_ext_ram_bss_end - &_ext_ram_bss_start))/1024);
  164. return heap_caps_add_region((intptr_t)&_ext_ram_bss_end, (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc()-1);
  165. #else
  166. ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", spiram_size_usable_for_malloc()/1024);
  167. return heap_caps_add_region((intptr_t)SOC_EXTRAM_DATA_LOW, (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc()-1);
  168. #endif
  169. }
  170. static uint8_t *dma_heap;
  171. esp_err_t esp_spiram_reserve_dma_pool(size_t size) {
  172. ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
  173. /* Pool may be allocated in multiple non-contiguous chunks, depending on available RAM */
  174. while (size > 0) {
  175. size_t next_size = heap_caps_get_largest_free_block(MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
  176. next_size = MIN(next_size, size);
  177. ESP_EARLY_LOGD(TAG, "Allocating block of size %d bytes", next_size);
  178. dma_heap = heap_caps_malloc(next_size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
  179. if (!dma_heap || next_size == 0) {
  180. return ESP_ERR_NO_MEM;
  181. }
  182. uint32_t caps[] = { 0, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT };
  183. esp_err_t e = heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+next_size-1);
  184. if (e != ESP_OK) {
  185. return e;
  186. }
  187. size -= next_size;
  188. }
  189. return ESP_OK;
  190. }
  191. size_t esp_spiram_get_size(void)
  192. {
  193. psram_size_t size=esp_spiram_get_chip_size();
  194. if (size==PSRAM_SIZE_16MBITS) return 2*1024*1024;
  195. if (size==PSRAM_SIZE_32MBITS) return 4*1024*1024;
  196. if (size==PSRAM_SIZE_64MBITS) return 8*1024*1024;
  197. return CONFIG_SPIRAM_SIZE;
  198. }
  199. /*
  200. Before flushing the cache, if psram is enabled as a memory-mapped thing, we need to write back the data in the cache to the psram first,
  201. otherwise it will get lost. For now, we just read 64/128K of random PSRAM memory to do this.
  202. Note that this routine assumes some unique mapping for the first 2 banks of the PSRAM memory range, as well as the
  203. 2 banks after the 2 MiB mark.
  204. */
  205. void IRAM_ATTR esp_spiram_writeback_cache(void)
  206. {
  207. int x;
  208. volatile int i=0;
  209. volatile uint8_t *psram=(volatile uint8_t*)SOC_EXTRAM_DATA_LOW;
  210. int cache_was_disabled=0;
  211. if (!spiram_inited) return;
  212. //We need cache enabled for this to work. Re-enable it if needed; make sure we
  213. //disable it again on exit as well.
  214. if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
  215. cache_was_disabled|=(1<<0);
  216. DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
  217. }
  218. #ifndef CONFIG_FREERTOS_UNICORE
  219. if (DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE)==0) {
  220. cache_was_disabled|=(1<<1);
  221. DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
  222. }
  223. #endif
  224. #if (PSRAM_MODE != PSRAM_VADDR_MODE_LOWHIGH)
  225. /*
  226. Single-core and even/odd mode only have 32K of cache evenly distributed over the address lines. We can clear
  227. the cache by just reading 64K worth of cache lines.
  228. */.
  229. for (x=0; x<1024*64; x+=32) {
  230. i+=psram[x];
  231. }
  232. #else
  233. /*
  234. Low/high psram cache mode uses one 32K cache for the lowest 2MiB of SPI flash and another 32K for the highest
  235. 2MiB. Clear this by reading from both regions.
  236. Note: this assumes the amount of external RAM is >2M. If it is 2M or less, what this code does is undefined. If
  237. we ever support external RAM chips of 2M or smaller, this may need adjusting.
  238. */
  239. for (x=0; x<1024*64; x+=32) {
  240. i+=psram[x];
  241. i+=psram[x+(1024*1024*2)];
  242. }
  243. #endif
  244. if (cache_was_disabled&(1<<0)) {
  245. while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) ;
  246. DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
  247. }
  248. #ifndef CONFIG_FREERTOS_UNICORE
  249. if (cache_was_disabled&(1<<1)) {
  250. while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1);
  251. DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
  252. }
  253. #endif
  254. }
  255. /**
  256. * @brief If SPI RAM(PSRAM) has been initialized
  257. *
  258. * @return true SPI RAM has been initialized successfully
  259. * @return false SPI RAM hasn't been initialized or initialized failed
  260. */
  261. bool esp_spiram_is_initialized(void)
  262. {
  263. return spiram_inited;
  264. }
  265. #endif