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 <stddef.h>
15 
16 #include <bootloader_flash_priv.h>
17 #include <esp_log.h>
18 #include <esp_flash_encrypt.h>
19 #include "sdkconfig.h"
20 #include "soc/soc_caps.h"
21 
22 #if CONFIG_IDF_TARGET_ESP32
23 #   include "soc/spi_struct.h"
24 #   include "soc/spi_reg.h"
25     /* SPI flash controller */
26 #   define SPIFLASH SPI1
27 #else
28 #   include "soc/spi_mem_struct.h"
29 #   include "soc/spi_mem_reg.h"
30     /* SPI flash controller */
31 #   define SPIFLASH SPIMEM1
32 #endif
33 
34 #if CONFIG_IDF_TARGET_ESP32S2
35 #include "esp32s2/rom/spi_flash.h"
36 #elif CONFIG_IDF_TARGET_ESP32S3
37 #include "esp32s3/rom/spi_flash.h"
38 #elif CONFIG_IDF_TARGET_ESP32C3
39 #include "esp32c3/rom/spi_flash.h"
40 #endif
41 
42 
43 #ifndef BOOTLOADER_BUILD
44 /* Normal app version maps to esp_spi_flash.h operations...
45  */
46 static const char *TAG = "bootloader_mmap";
47 
48 static spi_flash_mmap_handle_t map;
49 
bootloader_mmap_get_free_pages(void)50 uint32_t bootloader_mmap_get_free_pages(void)
51 {
52     return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
53 }
54 
bootloader_mmap(uint32_t src_addr,uint32_t size)55 const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
56 {
57     if (map) {
58         ESP_LOGE(TAG, "tried to bootloader_mmap twice");
59         return NULL; /* existing mapping in use... */
60     }
61     const void *result = NULL;
62     uint32_t src_page = src_addr & ~(SPI_FLASH_MMU_PAGE_SIZE - 1);
63     size += (src_addr - src_page);
64     esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map);
65     if (err != ESP_OK) {
66         ESP_LOGE(TAG, "spi_flash_mmap failed: 0x%x", err);
67         return NULL;
68     }
69     return (void *)((intptr_t)result + (src_addr - src_page));
70 }
71 
bootloader_munmap(const void * mapping)72 void bootloader_munmap(const void *mapping)
73 {
74     if (mapping && map) {
75         spi_flash_munmap(map);
76     }
77     map = 0;
78 }
79 
bootloader_flash_read(size_t src,void * dest,size_t size,bool allow_decrypt)80 esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size, bool allow_decrypt)
81 {
82     if (allow_decrypt && esp_flash_encryption_enabled()) {
83         return spi_flash_read_encrypted(src, dest, size);
84     } else {
85         return spi_flash_read(src, dest, size);
86     }
87 }
88 
bootloader_flash_write(size_t dest_addr,void * src,size_t size,bool write_encrypted)89 esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
90 {
91     if (write_encrypted) {
92 #if CONFIG_IDF_TARGET_ESP32
93         return spi_flash_write_encrypted(dest_addr, src, size);
94 #else
95         return esp_rom_spiflash_write_encrypted(dest_addr, src, size);
96 #endif
97     } else {
98         return spi_flash_write(dest_addr, src, size);
99     }
100 }
101 
bootloader_flash_erase_sector(size_t sector)102 esp_err_t bootloader_flash_erase_sector(size_t sector)
103 {
104     return spi_flash_erase_sector(sector);
105 }
106 
bootloader_flash_erase_range(uint32_t start_addr,uint32_t size)107 esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
108 {
109     return spi_flash_erase_range(start_addr, size);
110 }
111 
112 #else
113 /* Bootloader version, uses ROM functions only */
114 #if CONFIG_IDF_TARGET_ESP32
115 #include "esp32/rom/spi_flash.h"
116 #include "esp32/rom/cache.h"
117 #elif CONFIG_IDF_TARGET_ESP32S2
118 #include "esp32s2/rom/spi_flash.h"
119 #include "esp32s2/rom/cache.h"
120 #include "soc/cache_memory.h"
121 #elif CONFIG_IDF_TARGET_ESP32S3
122 #include "esp32s3/rom/spi_flash.h"
123 #include "esp32s3/rom/cache.h"
124 #include "soc/cache_memory.h"
125 #elif CONFIG_IDF_TARGET_ESP32C3
126 #include "esp32c3/rom/spi_flash.h"
127 #include "esp32c3/rom/cache.h"
128 #include "soc/cache_memory.h"
129 #endif
130 static const char *TAG = "bootloader_flash";
131 
132 #if CONFIG_IDF_TARGET_ESP32
133 /* Use first 50 blocks in MMU for bootloader_mmap,
134    50th block for bootloader_flash_read
135 */
136 #define MMU_BLOCK0_VADDR  SOC_DROM_LOW
137 #define MMU_SIZE          (0x320000)
138 #define MMU_BLOCK50_VADDR (MMU_BLOCK0_VADDR + MMU_SIZE)
139 #define FLASH_READ_VADDR MMU_BLOCK50_VADDR
140 
141 #else // !CONFIG_IDF_TARGET_ESP32
142 
143 /* Use first 63 blocks in MMU for bootloader_mmap,
144    63th block for bootloader_flash_read
145 */
146 #define MMU_BLOCK0_VADDR  SOC_DROM_LOW
147 #define MMU_SIZE          (0x3f0000)
148 #define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMU_SIZE)
149 #define FLASH_READ_VADDR MMU_BLOCK63_VADDR
150 #endif
151 
152 #define MMU_FREE_PAGES    (MMU_SIZE / FLASH_BLOCK_SIZE)
153 
154 static bool mapped;
155 
156 // Current bootloader mapping (ab)used for bootloader_read()
157 static uint32_t current_read_mapping = UINT32_MAX;
158 
bootloader_mmap_get_free_pages(void)159 uint32_t bootloader_mmap_get_free_pages(void)
160 {
161     /**
162      * Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads)
163      * Since, bootloader_mmap function below assumes it to be 0x320000 (50 pages), we can safely do this.
164      */
165     return MMU_FREE_PAGES;
166 }
167 
bootloader_mmap(uint32_t src_addr,uint32_t size)168 const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
169 {
170     if (mapped) {
171         ESP_LOGE(TAG, "tried to bootloader_mmap twice");
172         return NULL; /* can't map twice */
173     }
174     if (size > MMU_SIZE) {
175         ESP_LOGE(TAG, "bootloader_mmap excess size %x", size);
176         return NULL;
177     }
178 
179     uint32_t src_addr_aligned = src_addr & MMU_FLASH_MASK;
180     uint32_t count = bootloader_cache_pages_to_map(size, src_addr);
181 #if CONFIG_IDF_TARGET_ESP32
182     Cache_Read_Disable(0);
183     Cache_Flush(0);
184 #elif CONFIG_IDF_TARGET_ESP32S2
185     uint32_t autoload = Cache_Suspend_ICache();
186     Cache_Invalidate_ICache_All();
187 #elif CONFIG_IDF_TARGET_ESP32S3
188     uint32_t autoload = Cache_Suspend_DCache();
189     Cache_Invalidate_DCache_All();
190 #elif CONFIG_IDF_TARGET_ESP32C3
191     uint32_t autoload = Cache_Suspend_ICache();
192     Cache_Invalidate_ICache_All();
193 #endif
194     ESP_LOGD(TAG, "mmu set paddr=%08x count=%d size=%x src_addr=%x src_addr_aligned=%x",
195              src_addr & MMU_FLASH_MASK, count, size, src_addr, src_addr_aligned );
196 #if CONFIG_IDF_TARGET_ESP32
197     int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count);
198 #elif CONFIG_IDF_TARGET_ESP32S2
199     int e = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0);
200 #else // S3, C3
201     int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0);
202 #endif
203     if (e != 0) {
204         ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e);
205 #if CONFIG_IDF_TARGET_ESP32
206         Cache_Read_Enable(0);
207 #elif CONFIG_IDF_TARGET_ESP32S2
208         Cache_Resume_ICache(autoload);
209 #elif CONFIG_IDF_TARGET_ESP32S3
210         Cache_Resume_DCache(autoload);
211 #elif CONFIG_IDF_TARGET_ESP32C3
212         Cache_Resume_ICache(autoload);
213 #endif
214         return NULL;
215     }
216 #if CONFIG_IDF_TARGET_ESP32
217     Cache_Read_Enable(0);
218 #elif CONFIG_IDF_TARGET_ESP32S2
219     Cache_Resume_ICache(autoload);
220 #elif CONFIG_IDF_TARGET_ESP32S3
221     Cache_Resume_DCache(autoload);
222 #elif CONFIG_IDF_TARGET_ESP32C3
223     Cache_Resume_ICache(autoload);
224 #endif
225 
226     mapped = true;
227 
228     return (void *)(MMU_BLOCK0_VADDR + (src_addr - src_addr_aligned));
229 }
230 
bootloader_munmap(const void * mapping)231 void bootloader_munmap(const void *mapping)
232 {
233     if (mapped)  {
234 #if CONFIG_IDF_TARGET_ESP32
235         /* Full MMU reset */
236         Cache_Read_Disable(0);
237         Cache_Flush(0);
238         mmu_init(0);
239 #elif CONFIG_IDF_TARGET_ESP32S2
240         //TODO, save the autoload value.
241         Cache_Suspend_ICache();
242         Cache_Invalidate_ICache_All();
243         Cache_MMU_Init();
244 #elif CONFIG_IDF_TARGET_ESP32S3
245         Cache_Suspend_DCache();
246         Cache_Invalidate_DCache_All();
247         Cache_MMU_Init();
248 #elif CONFIG_IDF_TARGET_ESP32C3
249         //TODO, save the autoload value.
250         Cache_Suspend_ICache();
251         Cache_Invalidate_ICache_All();
252         Cache_MMU_Init();
253 #endif
254         mapped = false;
255         current_read_mapping = UINT32_MAX;
256     }
257 }
258 
spi_to_esp_err(esp_rom_spiflash_result_t r)259 static esp_err_t spi_to_esp_err(esp_rom_spiflash_result_t r)
260 {
261     switch (r) {
262     case ESP_ROM_SPIFLASH_RESULT_OK:
263         return ESP_OK;
264     case ESP_ROM_SPIFLASH_RESULT_ERR:
265         return ESP_ERR_FLASH_OP_FAIL;
266     case ESP_ROM_SPIFLASH_RESULT_TIMEOUT:
267         return ESP_ERR_FLASH_OP_TIMEOUT;
268     default:
269         return ESP_FAIL;
270     }
271 }
272 
bootloader_flash_read_no_decrypt(size_t src_addr,void * dest,size_t size)273 static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, size_t size)
274 {
275 #if CONFIG_IDF_TARGET_ESP32
276     Cache_Read_Disable(0);
277     Cache_Flush(0);
278 #elif CONFIG_IDF_TARGET_ESP32S2
279     uint32_t autoload = Cache_Suspend_ICache();
280 #elif CONFIG_IDF_TARGET_ESP32S3
281     uint32_t autoload = Cache_Suspend_DCache();
282 #elif CONFIG_IDF_TARGET_ESP32C3
283     uint32_t autoload = Cache_Suspend_ICache();
284 #endif
285     esp_rom_spiflash_result_t r = esp_rom_spiflash_read(src_addr, dest, size);
286 #if CONFIG_IDF_TARGET_ESP32
287     Cache_Read_Enable(0);
288 #elif CONFIG_IDF_TARGET_ESP32S2
289     Cache_Resume_ICache(autoload);
290 #elif CONFIG_IDF_TARGET_ESP32S3
291     Cache_Resume_DCache(autoload);
292 #elif CONFIG_IDF_TARGET_ESP32C3
293     Cache_Resume_ICache(autoload);
294 #endif
295 
296     return spi_to_esp_err(r);
297 }
298 
bootloader_flash_read_allow_decrypt(size_t src_addr,void * dest,size_t size)299 static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest, size_t size)
300 {
301     uint32_t *dest_words = (uint32_t *)dest;
302 
303     for (size_t word = 0; word < size / 4; word++) {
304         uint32_t word_src = src_addr + word * 4;  /* Read this offset from flash */
305         uint32_t map_at = word_src & MMU_FLASH_MASK; /* Map this 64KB block from flash */
306         uint32_t *map_ptr;
307         if (map_at != current_read_mapping) {
308             /* Move the 64KB mmu mapping window to fit map_at */
309 #if CONFIG_IDF_TARGET_ESP32
310             Cache_Read_Disable(0);
311             Cache_Flush(0);
312 #elif CONFIG_IDF_TARGET_ESP32S2
313             uint32_t autoload = Cache_Suspend_ICache();
314             Cache_Invalidate_ICache_All();
315 #elif CONFIG_IDF_TARGET_ESP32S3
316             uint32_t autoload = Cache_Suspend_DCache();
317             Cache_Invalidate_DCache_All();
318 #elif CONFIG_IDF_TARGET_ESP32C3
319             uint32_t autoload = Cache_Suspend_ICache();
320             Cache_Invalidate_ICache_All();
321 #endif
322             ESP_LOGD(TAG, "mmu set block paddr=0x%08x (was 0x%08x)", map_at, current_read_mapping);
323 #if CONFIG_IDF_TARGET_ESP32
324             int e = cache_flash_mmu_set(0, 0, FLASH_READ_VADDR, map_at, 64, 1);
325 #elif CONFIG_IDF_TARGET_ESP32S2
326             int e = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
327 #elif CONFIG_IDF_TARGET_ESP32S3
328             int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
329 #elif CONFIG_IDF_TARGET_ESP32C3
330             int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
331 #endif
332             if (e != 0) {
333                 ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e);
334 #if CONFIG_IDF_TARGET_ESP32
335                 Cache_Read_Enable(0);
336 #elif CONFIG_IDF_TARGET_ESP32S2
337                 Cache_Resume_ICache(autoload);
338 #elif CONFIG_IDF_TARGET_ESP32S3
339                 Cache_Resume_DCache(autoload);
340 #elif CONFIG_IDF_TARGET_ESP32C3
341                 Cache_Resume_ICache(autoload);
342 #endif
343                 return ESP_FAIL;
344             }
345             current_read_mapping = map_at;
346 #if CONFIG_IDF_TARGET_ESP32
347             Cache_Read_Enable(0);
348 #elif CONFIG_IDF_TARGET_ESP32S2
349             Cache_Resume_ICache(autoload);
350 #elif CONFIG_IDF_TARGET_ESP32S3
351             Cache_Resume_DCache(autoload);
352 #elif CONFIG_IDF_TARGET_ESP32C3
353             Cache_Resume_ICache(autoload);
354 #endif
355         }
356         map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at));
357         dest_words[word] = *map_ptr;
358     }
359     return ESP_OK;
360 }
361 
bootloader_flash_read(size_t src_addr,void * dest,size_t size,bool allow_decrypt)362 esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt)
363 {
364     if (src_addr & 3) {
365         ESP_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr);
366         return ESP_FAIL;
367     }
368     if (size & 3) {
369         ESP_LOGE(TAG, "bootloader_flash_read size 0x%x not 4-byte aligned", size);
370         return ESP_FAIL;
371     }
372     if ((intptr_t)dest & 3) {
373         ESP_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest);
374         return ESP_FAIL;
375     }
376 
377     if (allow_decrypt) {
378         return bootloader_flash_read_allow_decrypt(src_addr, dest, size);
379     } else {
380         return bootloader_flash_read_no_decrypt(src_addr, dest, size);
381     }
382 }
383 
bootloader_flash_write(size_t dest_addr,void * src,size_t size,bool write_encrypted)384 esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
385 {
386     esp_err_t err;
387     size_t alignment = write_encrypted ? 32 : 4;
388     if ((dest_addr % alignment) != 0) {
389         ESP_LOGE(TAG, "bootloader_flash_write dest_addr 0x%x not %d-byte aligned", dest_addr, alignment);
390         return ESP_FAIL;
391     }
392     if ((size % alignment) != 0) {
393         ESP_LOGE(TAG, "bootloader_flash_write size 0x%x not %d-byte aligned", size, alignment);
394         return ESP_FAIL;
395     }
396     if (((intptr_t)src % 4) != 0) {
397         ESP_LOGE(TAG, "bootloader_flash_write src 0x%x not 4 byte aligned", (intptr_t)src);
398         return ESP_FAIL;
399     }
400 
401     err = spi_to_esp_err(esp_rom_spiflash_unlock());
402     if (err != ESP_OK) {
403         return err;
404     }
405 
406     if (write_encrypted) {
407         return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size));
408     } else {
409         return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size));
410     }
411 }
412 
bootloader_flash_erase_sector(size_t sector)413 esp_err_t bootloader_flash_erase_sector(size_t sector)
414 {
415     return spi_to_esp_err(esp_rom_spiflash_erase_sector(sector));
416 }
417 
bootloader_flash_erase_range(uint32_t start_addr,uint32_t size)418 esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
419 {
420     if (start_addr % FLASH_SECTOR_SIZE != 0) {
421         return ESP_ERR_INVALID_ARG;
422     }
423     if (size % FLASH_SECTOR_SIZE != 0) {
424         return ESP_ERR_INVALID_SIZE;
425     }
426     size_t start = start_addr / FLASH_SECTOR_SIZE;
427     size_t end = start + size / FLASH_SECTOR_SIZE;
428     const size_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
429 
430     esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK;
431     for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) {
432         if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) {
433             rc = esp_rom_spiflash_erase_block(sector / sectors_per_block);
434             sector += sectors_per_block;
435         } else {
436             rc = esp_rom_spiflash_erase_sector(sector);
437             ++sector;
438         }
439     }
440     return spi_to_esp_err(rc);
441 }
442 
443 #endif
444 
445 #ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here
446 extern uint8_t g_rom_spiflash_dummy_len_plus[];
447 #endif
bootloader_execute_flash_command(uint8_t command,uint32_t mosi_data,uint8_t mosi_len,uint8_t miso_len)448 uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
449 {
450     uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
451 #if CONFIG_IDF_TARGET_ESP32
452     SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
453 #else
454     SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
455 #endif
456     SPIFLASH.user.usr_dummy = 0;
457     SPIFLASH.user.usr_addr = 0;
458     SPIFLASH.user.usr_command = 1;
459     SPIFLASH.user2.usr_command_bitlen = 7;
460 
461     SPIFLASH.user2.usr_command_value = command;
462     SPIFLASH.user.usr_miso = miso_len > 0;
463 #if CONFIG_IDF_TARGET_ESP32
464     SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
465 #else
466     SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
467 #endif
468     SPIFLASH.user.usr_mosi = mosi_len > 0;
469 #if CONFIG_IDF_TARGET_ESP32
470     SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
471 #else
472     SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
473 #endif
474     SPIFLASH.data_buf[0] = mosi_data;
475 
476     if (g_rom_spiflash_dummy_len_plus[1]) {
477         /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
478         if (miso_len > 0) {
479             SPIFLASH.user.usr_dummy = 1;
480             SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
481         } else {
482             SPIFLASH.user.usr_dummy = 0;
483             SPIFLASH.user1.usr_dummy_cyclelen = 0;
484         }
485     }
486 
487     SPIFLASH.cmd.usr = 1;
488     while (SPIFLASH.cmd.usr != 0) {
489     }
490 
491     SPIFLASH.ctrl.val = old_ctrl_reg;
492     return SPIFLASH.data_buf[0];
493 }
494 
bootloader_enable_wp(void)495 void bootloader_enable_wp(void)
496 {
497     bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);   /* Exit OTP mode */
498 }
499 
500 #if SOC_CACHE_SUPPORT_WRAP
bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)501 esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
502 {
503     uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val;
504     uint32_t reg_bkp_usr  = SPIFLASH.user.val;
505     SPIFLASH.user.fwrite_dio = 0;
506     SPIFLASH.user.fwrite_dual = 0;
507     SPIFLASH.user.fwrite_qio = 1;
508     SPIFLASH.user.fwrite_quad = 0;
509     SPIFLASH.ctrl.fcmd_dual = 0;
510     SPIFLASH.ctrl.fcmd_quad = 0;
511     SPIFLASH.user.usr_dummy = 0;
512     SPIFLASH.user.usr_addr = 1;
513     SPIFLASH.user.usr_command = 1;
514     SPIFLASH.user2.usr_command_bitlen = 7;
515     SPIFLASH.user2.usr_command_value = CMD_WRAP;
516     SPIFLASH.user1.usr_addr_bitlen = 23;
517     SPIFLASH.addr = 0;
518     SPIFLASH.user.usr_miso = 0;
519     SPIFLASH.user.usr_mosi = 1;
520     SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7;
521     SPIFLASH.data_buf[0] = (uint32_t) mode << 4;;
522     SPIFLASH.cmd.usr = 1;
523     while(SPIFLASH.cmd.usr != 0)
524     { }
525 
526     SPIFLASH.ctrl.val = reg_bkp_ctrl;
527     SPIFLASH.user.val = reg_bkp_usr;
528     return ESP_OK;
529 }
530 #endif //SOC_CACHE_SUPPORT_WRAP
531