flash_ops.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdlib.h>
  15. #include <assert.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <freertos/FreeRTOS.h>
  19. #include <freertos/task.h>
  20. #include <freertos/semphr.h>
  21. #include <rom/spi_flash.h>
  22. #include <rom/cache.h>
  23. #include <soc/soc.h>
  24. #include <soc/dport_reg.h>
  25. #include "sdkconfig.h"
  26. #include "esp_ipc.h"
  27. #include "esp_attr.h"
  28. #include "esp_spi_flash.h"
  29. #include "esp_log.h"
  30. #include "cache_utils.h"
  31. /* bytes erased by SPIEraseBlock() ROM function */
  32. #define BLOCK_ERASE_SIZE 32768
  33. #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
  34. static const char* TAG = "spi_flash";
  35. static spi_flash_counters_t s_flash_stats;
  36. #define COUNTER_START() uint32_t ts_begin = xthal_get_ccount()
  37. #define COUNTER_STOP(counter) \
  38. do{ \
  39. s_flash_stats.counter.count++; \
  40. s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); \
  41. } while(0)
  42. #define COUNTER_ADD_BYTES(counter, size) \
  43. do { \
  44. s_flash_stats.counter.bytes += size; \
  45. } while (0)
  46. #else
  47. #define COUNTER_START()
  48. #define COUNTER_STOP(counter)
  49. #define COUNTER_ADD_BYTES(counter, size)
  50. #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
  51. static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc);
  52. void spi_flash_init()
  53. {
  54. spi_flash_init_lock();
  55. #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
  56. spi_flash_reset_counters();
  57. #endif
  58. }
  59. size_t spi_flash_get_chip_size()
  60. {
  61. return g_rom_flashchip.chip_size;
  62. }
  63. SpiFlashOpResult IRAM_ATTR spi_flash_unlock()
  64. {
  65. static bool unlocked = false;
  66. if (!unlocked) {
  67. SpiFlashOpResult rc = SPIUnlock();
  68. if (rc != SPI_FLASH_RESULT_OK) {
  69. return rc;
  70. }
  71. unlocked = true;
  72. }
  73. return SPI_FLASH_RESULT_OK;
  74. }
  75. esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec)
  76. {
  77. return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
  78. }
  79. esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
  80. {
  81. if (start_addr % SPI_FLASH_SEC_SIZE != 0) {
  82. return ESP_ERR_INVALID_ARG;
  83. }
  84. if (size % SPI_FLASH_SEC_SIZE != 0) {
  85. return ESP_ERR_INVALID_SIZE;
  86. }
  87. if (size + start_addr > spi_flash_get_chip_size()) {
  88. return ESP_ERR_INVALID_SIZE;
  89. }
  90. size_t start = start_addr / SPI_FLASH_SEC_SIZE;
  91. size_t end = start + size / SPI_FLASH_SEC_SIZE;
  92. const size_t sectors_per_block = BLOCK_ERASE_SIZE / SPI_FLASH_SEC_SIZE;
  93. COUNTER_START();
  94. spi_flash_disable_interrupts_caches_and_other_cpu();
  95. SpiFlashOpResult rc;
  96. rc = spi_flash_unlock();
  97. if (rc == SPI_FLASH_RESULT_OK) {
  98. for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) {
  99. if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) {
  100. rc = SPIEraseBlock(sector / sectors_per_block);
  101. sector += sectors_per_block;
  102. COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE);
  103. }
  104. else {
  105. rc = SPIEraseSector(sector);
  106. ++sector;
  107. COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
  108. }
  109. }
  110. }
  111. spi_flash_enable_interrupts_caches_and_other_cpu();
  112. COUNTER_STOP(erase);
  113. return spi_flash_translate_rc(rc);
  114. }
  115. esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t size)
  116. {
  117. // Destination alignment is also checked in ROM code, but we can give
  118. // better error code here
  119. // TODO: add handling of unaligned destinations
  120. uint8_t *temp_write_buf = NULL;
  121. uint8_t pad_head = 0;
  122. uint8_t pad_end = 0;
  123. SpiFlashOpResult rc;
  124. // Out of bound writes are checked in ROM code, but we can give better
  125. // error code here
  126. if (dest_addr + size > g_rom_flashchip.chip_size) {
  127. return ESP_ERR_INVALID_SIZE;
  128. }
  129. while(size >= 1024) {
  130. // max need pad byte num for 1024 is 4
  131. temp_write_buf = (uint8_t*)malloc(1024 + 4);
  132. if(temp_write_buf == NULL) {
  133. return ESP_ERR_NO_MEM;
  134. }
  135. if(dest_addr%4 != 0) {
  136. pad_head = dest_addr%4;
  137. pad_end = 4 - pad_head;
  138. }
  139. memset(temp_write_buf,0xFF,pad_head);
  140. memcpy(temp_write_buf + pad_head ,src,1024);
  141. memset(temp_write_buf + pad_head + 1024, 0xFF,pad_end);
  142. COUNTER_START();
  143. spi_flash_disable_interrupts_caches_and_other_cpu();
  144. rc = spi_flash_unlock();
  145. if (rc == SPI_FLASH_RESULT_OK) {
  146. rc = SPIWrite((uint32_t) (dest_addr - pad_head), (const uint32_t*) temp_write_buf, (int32_t) (1024 + pad_head + pad_end));
  147. COUNTER_ADD_BYTES(write, 1024 + pad_head + pad_end);
  148. }
  149. COUNTER_STOP(write);
  150. spi_flash_enable_interrupts_caches_and_other_cpu();
  151. if(rc != ESP_OK) {
  152. free(temp_write_buf);
  153. temp_write_buf = NULL;
  154. return spi_flash_translate_rc(rc);
  155. }
  156. free(temp_write_buf);
  157. temp_write_buf = NULL;
  158. size -= 1024;
  159. dest_addr += 1024;
  160. src = (uint8_t*)src + 1024;
  161. }
  162. if(size > 0) {
  163. // max need pad byte num for rand size is 6
  164. temp_write_buf = (uint8_t*)malloc(size + 6);
  165. if(temp_write_buf == NULL) {
  166. return ESP_ERR_NO_MEM;
  167. }
  168. if(dest_addr%4 != 0) {
  169. pad_head = dest_addr%4;
  170. }
  171. if ((pad_head + size)%4 != 0){
  172. pad_end = 4 - (pad_head + size) % 4;
  173. }
  174. memset(temp_write_buf,0xFF,pad_head);
  175. memcpy(temp_write_buf + pad_head, src, size);
  176. memset(temp_write_buf + pad_head + size, 0xFF,pad_end);
  177. COUNTER_START();
  178. spi_flash_disable_interrupts_caches_and_other_cpu();
  179. rc = spi_flash_unlock();
  180. if (rc == SPI_FLASH_RESULT_OK) {
  181. rc = SPIWrite((uint32_t) (dest_addr - pad_head), (const uint32_t*) temp_write_buf, (int32_t) (size + pad_head + pad_end));
  182. COUNTER_ADD_BYTES(write, size + pad_head + pad_end);
  183. }
  184. COUNTER_STOP(write);
  185. spi_flash_enable_interrupts_caches_and_other_cpu();
  186. if(rc != ESP_OK) {
  187. free(temp_write_buf);
  188. temp_write_buf = NULL;
  189. return spi_flash_translate_rc(rc);
  190. }
  191. free(temp_write_buf);
  192. temp_write_buf = NULL;
  193. size = 0;
  194. dest_addr += size;
  195. src = (uint8_t*)src + size;
  196. return spi_flash_translate_rc(rc);
  197. }
  198. return spi_flash_translate_rc(SPI_FLASH_RESULT_OK);
  199. }
  200. esp_err_t IRAM_ATTR spi_flash_read(size_t src_addr, void *dest, size_t size)
  201. {
  202. // TODO: replace this check with code which deals with unaligned destinations
  203. if (((ptrdiff_t) dest) % 4 != 0) {
  204. return ESP_ERR_INVALID_ARG;
  205. }
  206. // Source alignment is also checked in ROM code, but we can give
  207. // better error code here
  208. // TODO: add handling of unaligned destinations
  209. if (src_addr % 4 != 0) {
  210. return ESP_ERR_INVALID_ARG;
  211. }
  212. if (size % 4 != 0) {
  213. return ESP_ERR_INVALID_SIZE;
  214. }
  215. // Out of bound reads are checked in ROM code, but we can give better
  216. // error code here
  217. if (src_addr + size > g_rom_flashchip.chip_size) {
  218. return ESP_ERR_INVALID_SIZE;
  219. }
  220. COUNTER_START();
  221. spi_flash_disable_interrupts_caches_and_other_cpu();
  222. SpiFlashOpResult rc = SPIRead((uint32_t) src_addr, (uint32_t*) dest, (int32_t) size);
  223. COUNTER_ADD_BYTES(read, size);
  224. spi_flash_enable_interrupts_caches_and_other_cpu();
  225. COUNTER_STOP(read);
  226. return spi_flash_translate_rc(rc);
  227. }
  228. static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc)
  229. {
  230. switch (rc) {
  231. case SPI_FLASH_RESULT_OK:
  232. return ESP_OK;
  233. case SPI_FLASH_RESULT_TIMEOUT:
  234. return ESP_ERR_FLASH_OP_TIMEOUT;
  235. case SPI_FLASH_RESULT_ERR:
  236. default:
  237. return ESP_ERR_FLASH_OP_FAIL;
  238. }
  239. }
  240. #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
  241. static inline void dump_counter(spi_flash_counter_t* counter, const char* name)
  242. {
  243. ESP_LOGI(TAG, "%s count=%8d time=%8dms bytes=%8d\n", name,
  244. counter->count, counter->time, counter->bytes);
  245. }
  246. const spi_flash_counters_t* spi_flash_get_counters()
  247. {
  248. return &s_flash_stats;
  249. }
  250. void spi_flash_reset_counters()
  251. {
  252. memset(&s_flash_stats, 0, sizeof(s_flash_stats));
  253. }
  254. void spi_flash_dump_counters()
  255. {
  256. dump_counter(&s_flash_stats.read, "read ");
  257. dump_counter(&s_flash_stats.write, "write");
  258. dump_counter(&s_flash_stats.erase, "erase");
  259. }
  260. #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS