1
6
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
58
59
60
61
65
66
67
68
69
73
74
75
76
83
84
92
93
101
102
107
108
113
114
115
116
117
118
119
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
147
148
149
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
176
177
178
179
183
187
188
189
190
191
197
201
202
210
211
212
213
222
229
230
231
235
236
237
238
239
240
244
245
246
247
248
249
250
251
252
253
254
255
259
260
262
263
264
265
266
267
268
281
282
283
284
285
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
322
323
324
325
329
330
332
333
334
335
336
337
338
339
343
344
345
346
347
348
349
350
351
352
353
357
361
365
366
371
372
373
374
375
376
377
381
385
389
390
391
394
395
400
401
402
406
407
408
409
412
415
416
417
418
419
420
429
430
431
432
433
434
435
436
437
443
449
455
461
467
473
476
477
478
479
480
481
482
483
484
485
486
490
491
492
496
497
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
522
523
524
525
528
529
530
531
532
533
534
535
536
537
538
541
542
543
544
545
546
547
548
554
555
561
562
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
601
602
603
604
605
606
607
608
609
610
612
613
614
615
616
617
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
653
654
660
661
666
667
670
671
672
673
674
675
676
677
679
680
681
682
683
684
685
686
687
688
689
692
693
694
707
708
709
710
711
712
713
714
718
719
720
721
722
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
745
746
747
748
749
750
766
767
768
769
770
771
772
773
774
775
776
777
778
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
816
830
831
/* ... */
#include <stddef.h>
#include <bootloader_flash_priv.h>
#include <esp_log.h>
#include <esp_flash_encrypt.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "hal/efuse_ll.h"
#include "hal/efuse_hal.h"8 includes
#ifndef BOOTLOADER_BUILD
#include "spi_flash_mmap.h"
#endif
#include "hal/spi_flash_ll.h"
#include "rom/spi_flash.h"
#if !CONFIG_IDF_TARGET_ESP32
#include "hal/spimem_flash_ll.h"
#endif
#include "esp_flash.h"
#include "esp_rom_spiflash.h"
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
#define ENCRYPTION_IS_VIRTUAL (!efuse_hal_flash_encryption_enabled())
#else
#define ENCRYPTION_IS_VIRTUAL 0
#endif
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
#define ISSI_ID 0x9D
#define MXIC_ID 0xC2
#define GD_Q_ID_HIGH 0xC8
#define GD_Q_ID_MID 0x40
#define GD_Q_ID_LOW 0x16
#define ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
#define ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2 BIT1
#define ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE BIT9 9 defines
#ifndef BOOTLOADER_BUILD
/* ... */
static const char *TAG = "bootloader_mmap";
static spi_flash_mmap_handle_t map;
uint32_t bootloader_mmap_get_free_pages(void)
{
return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
}{ ... }
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
{
if (map) {
ESP_EARLY_LOGE(TAG, "tried to bootloader_mmap twice");
return NULL;
}{...}
const void *result = NULL;
uint32_t src_page = src_addr & ~(SPI_FLASH_MMU_PAGE_SIZE - 1);
size += (src_addr - src_page);
esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "spi_flash_mmap failed: 0x%x", err);
return NULL;
}{...}
return (void *)((intptr_t)result + (src_addr - src_page));
}{ ... }
void bootloader_munmap(const void *mapping)
{
if (mapping && map) {
spi_flash_munmap(map);
}{...}
map = 0;
}{ ... }
esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size, bool allow_decrypt)
{
if (allow_decrypt && esp_flash_encryption_enabled()) {
return esp_flash_read_encrypted(NULL, src, dest, size);
}{...} else {
return esp_flash_read(NULL, dest, src, size);
}{...}
}{ ... }
esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
{
if (write_encrypted && !ENCRYPTION_IS_VIRTUAL) {
return esp_flash_write_encrypted(NULL, dest_addr, src, size);
}{...} else {
return esp_flash_write(NULL, src, dest_addr, size);
}{...}
}{ ... }
esp_err_t bootloader_flash_erase_sector(size_t sector)
{
return esp_flash_erase_region(NULL, sector * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
}{ ... }
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
{
return esp_flash_erase_region(NULL, start_addr, size);
}{ ... }
/* ... */#else
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/cache.h"
#endif
#include "esp_rom_spiflash.h"
#include "esp_rom_sys.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"6 includes
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/opi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32P4
#include "esp32p4/rom/opi_flash.h"
#endif
static const char *TAG = "bootloader_flash";
#if CONFIG_IDF_TARGET_ESP32
/* ... */
#define MMU_BLOCK0_VADDR SOC_DROM_LOW
#define MMAP_MMU_SIZE (0x320000)
#define MMU_BLOCK50_VADDR (MMU_BLOCK0_VADDR + MMAP_MMU_SIZE)
#define FLASH_READ_VADDR MMU_BLOCK50_VADDR
/* ... */
#else
/* ... */
#define MMU_BLOCK0_VADDR SOC_DROM_LOW
#if CONFIG_IDF_TARGET_ESP32S2
/* ... */
#define MMAP_MMU_SIZE (SOC_DRAM0_CACHE_ADDRESS_HIGH - SOC_DRAM0_CACHE_ADDRESS_LOW) /* ... */
#else
#define MMAP_MMU_SIZE (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_DRAM_FLASH_ADDRESS_LOW)
#endif
#define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMAP_MMU_SIZE - SPI_FLASH_MMU_PAGE_SIZE)
#define FLASH_READ_VADDR MMU_BLOCK63_VADDR/* ... */
#endif
#define MMU_FREE_PAGES (MMAP_MMU_SIZE / CONFIG_MMU_PAGE_SIZE)
static bool mapped;
static uint32_t current_read_mapping = UINT32_MAX;
uint32_t bootloader_mmap_get_free_pages(void)
{
/* ... */
return MMU_FREE_PAGES;
}{...}
const void *bootloader_mmap(uint32_t src_paddr, uint32_t size)
{
if (mapped) {
ESP_EARLY_LOGE(TAG, "tried to bootloader_mmap twice");
return NULL;
}{...}
if (size > MMAP_MMU_SIZE) {
ESP_EARLY_LOGE(TAG, "bootloader_mmap excess size %" PRIx32, size);
return NULL;
}{...}
uint32_t src_paddr_aligned = src_paddr & MMU_FLASH_MASK;
uint32_t size_after_paddr_aligned = (src_paddr - src_paddr_aligned) + size;
/* ... */
if (mmu_ll_check_valid_ext_vaddr_region(0, MMU_BLOCK0_VADDR, size_after_paddr_aligned, MMU_VADDR_DATA | MMU_VADDR_INSTRUCTION) == 0) {
ESP_EARLY_LOGE(TAG, "vaddr not valid");
return NULL;
}{...}
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Disable(0);
Cache_Flush(0);/* ... */
#else
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
stop cache to do the MMU mapping
ESP_EARLY_LOGD(TAG, "rodata starts from paddr=0x%08" PRIx32 ", size=0x%" PRIx32 ", will be mapped to vaddr=0x%08" PRIx32, src_paddr, size, (uint32_t)MMU_BLOCK0_VADDR);
#if CONFIG_IDF_TARGET_ESP32
uint32_t count = GET_REQUIRED_MMU_PAGES(size, src_paddr);
int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_paddr_aligned, 64, count);
ESP_EARLY_LOGV(TAG, "after mapping, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", src_paddr_aligned, (uint32_t)MMU_BLOCK0_VADDR, count * SPI_FLASH_MMU_PAGE_SIZE);
if (e != 0) {
ESP_EARLY_LOGE(TAG, "cache_flash_mmu_set failed: %d", e);
Cache_Read_Enable(0);
return NULL;
}{...}
/* ... */#else
/* ... */
uint32_t actual_mapped_len = 0;
mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_BLOCK0_VADDR, src_paddr_aligned, size_after_paddr_aligned, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "after mapping, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", src_paddr_aligned, (uint32_t)MMU_BLOCK0_VADDR, actual_mapped_len);/* ... */
#endif
/* ... */
Do mapping
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Enable(0);
#else
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, MMU_BLOCK0_VADDR, actual_mapped_len);
#endif
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);/* ... */
#endif
mapped = true;
return (void *)(MMU_BLOCK0_VADDR + (src_paddr - src_paddr_aligned));
}{...}
void bootloader_munmap(const void *mapping)
{
if (mapped) {
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Disable(0);
Cache_Flush(0);
mmu_init(0);/* ... */
#else
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
mmu_hal_unmap_all();/* ... */
#endif
mapped = false;
current_read_mapping = UINT32_MAX;
}{...}
}{...}
static esp_err_t spi_to_esp_err(esp_rom_spiflash_result_t r)
{
switch (r) {
case ESP_ROM_SPIFLASH_RESULT_OK:
return ESP_OK;...
case ESP_ROM_SPIFLASH_RESULT_ERR:
return ESP_ERR_FLASH_OP_FAIL;...
case ESP_ROM_SPIFLASH_RESULT_TIMEOUT:
return ESP_ERR_FLASH_OP_TIMEOUT;...
default:
return ESP_FAIL;...
}{...}
}{...}
static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, size_t size)
{
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Disable(0);
Cache_Flush(0);/* ... */
#else
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
esp_rom_spiflash_result_t r = esp_rom_spiflash_read(src_addr, dest, size);
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Enable(0);
#else
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
return spi_to_esp_err(r);
}{...}
static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest, size_t size)
{
uint32_t *dest_words = (uint32_t *)dest;
for (size_t word = 0; word < size / 4; word++) {
uint32_t word_src = src_addr + word * 4;
uint32_t map_at = word_src & MMU_FLASH_MASK;
uint32_t *map_ptr;
if (map_at != current_read_mapping) {
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Disable(0);
Cache_Flush(0);/* ... */
#else
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
Stop cache for mapping
ESP_EARLY_LOGD(TAG, "mmu set block paddr=0x%08" PRIx32 " (was 0x%08" PRIx32 ")", map_at, current_read_mapping);
#if CONFIG_IDF_TARGET_ESP32
int e __attribute__((unused)) = cache_flash_mmu_set(0, 0, FLASH_READ_VADDR, map_at, 64, 1);
assert(e == 0);/* ... */
#else
uint32_t actual_mapped_len = 0;
mmu_hal_map_region(0, MMU_TARGET_FLASH0, FLASH_READ_VADDR, map_at, SPI_FLASH_MMU_PAGE_SIZE - 1, &actual_mapped_len);/* ... */
#endif
current_read_mapping = map_at;
Do mapping
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Enable(0);
#else
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, MMU_BLOCK0_VADDR, actual_mapped_len);
#endif
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);/* ... */
#endif
}{...}
map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at));
dest_words[word] = *map_ptr;
}{...}
return ESP_OK;
}{...}
esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt)
{
if (src_addr & 3) {
ESP_EARLY_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr);
return ESP_FAIL;
}{...}
if (size & 3) {
ESP_EARLY_LOGE(TAG, "bootloader_flash_read size 0x%x not 4-byte aligned", size);
return ESP_FAIL;
}{...}
if ((intptr_t)dest & 3) {
ESP_EARLY_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest);
return ESP_FAIL;
}{...}
if (allow_decrypt) {
return bootloader_flash_read_allow_decrypt(src_addr, dest, size);
}{...} else {
return bootloader_flash_read_no_decrypt(src_addr, dest, size);
}{...}
}{...}
esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
{
esp_err_t err;
size_t alignment = write_encrypted ? 32 : 4;
if ((dest_addr % alignment) != 0) {
ESP_EARLY_LOGE(TAG, "bootloader_flash_write dest_addr 0x%x not %d-byte aligned", dest_addr, alignment);
return ESP_FAIL;
}{...}
if ((size % alignment) != 0) {
ESP_EARLY_LOGE(TAG, "bootloader_flash_write size 0x%x not %d-byte aligned", size, alignment);
return ESP_FAIL;
}{...}
if (((intptr_t)src % 4) != 0) {
ESP_EARLY_LOGE(TAG, "bootloader_flash_write src 0x%x not 4 byte aligned", (intptr_t)src);
return ESP_FAIL;
}{...}
err = bootloader_flash_unlock();
if (err != ESP_OK) {
return err;
}{...}
if (write_encrypted && !ENCRYPTION_IS_VIRTUAL) {
return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size));
}{...} else {
return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size));
}{...}
}{...}
esp_err_t bootloader_flash_erase_sector(size_t sector)
{
return spi_to_esp_err(esp_rom_spiflash_erase_sector(sector));
}{...}
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
{
if (start_addr % FLASH_SECTOR_SIZE != 0) {
return ESP_ERR_INVALID_ARG;
}{...}
if (size % FLASH_SECTOR_SIZE != 0) {
return ESP_ERR_INVALID_SIZE;
}{...}
size_t start = start_addr / FLASH_SECTOR_SIZE;
size_t end = start + size / FLASH_SECTOR_SIZE;
const size_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK;
for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) {
if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) {
rc = esp_rom_spiflash_erase_block(sector / sectors_per_block);
sector += sectors_per_block;
}{...} else {
rc = esp_rom_spiflash_erase_sector(sector);
++sector;
}{...}
}{...}
return spi_to_esp_err(rc);
}{...}
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH || CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_OCTAL_FLASH
void bootloader_flash_32bits_address_map_enable(esp_rom_spiflash_read_mode_t flash_mode)
{
esp_rom_opiflash_spi0rd_t cache_rd = {};
switch (flash_mode) {
case ESP_ROM_SPIFLASH_DOUT_MODE:
cache_rd.addr_bit_len = 32;
cache_rd.dummy_bit_len = 8;
cache_rd.cmd = CMD_FASTRD_DUAL_4B;
cache_rd.cmd_bit_len = 8;
break;...
case ESP_ROM_SPIFLASH_DIO_MODE:
cache_rd.addr_bit_len = 32;
cache_rd.dummy_bit_len = 4;
cache_rd.cmd = CMD_FASTRD_DIO_4B;
cache_rd.cmd_bit_len = 8;
break;...
case ESP_ROM_SPIFLASH_QOUT_MODE:
cache_rd.addr_bit_len = 32;
cache_rd.dummy_bit_len = 8;
cache_rd.cmd = CMD_FASTRD_QUAD_4B;
cache_rd.cmd_bit_len = 8;
break;...
case ESP_ROM_SPIFLASH_QIO_MODE:
cache_rd.addr_bit_len = 32;
cache_rd.dummy_bit_len = 6;
cache_rd.cmd = CMD_FASTRD_QIO_4B;
cache_rd.cmd_bit_len = 8;
break;...
case ESP_ROM_SPIFLASH_FASTRD_MODE:
cache_rd.addr_bit_len = 32;
cache_rd.dummy_bit_len = 8;
cache_rd.cmd = CMD_FASTRD_4B;
cache_rd.cmd_bit_len = 8;
break;...
case ESP_ROM_SPIFLASH_SLOWRD_MODE:
cache_rd.addr_bit_len = 32;
cache_rd.dummy_bit_len = 0;
cache_rd.cmd = CMD_SLOWRD_4B;
cache_rd.cmd_bit_len = 8;
break;...
default:
assert(false);
break;...
}{...}
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
esp_rom_opiflash_cache_mode_config(flash_mode, &cache_rd);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
}{...}
/* ... */#endif
/* ... */
#endif
FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == ISSI_ID;
}{ ... }
FORCE_INLINE_ATTR bool is_gd_q_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == GD_Q_ID_HIGH && BYTESHIFT(chip->device_id, 1) == GD_Q_ID_MID && BYTESHIFT(chip->device_id, 0) >= GD_Q_ID_LOW;
}{ ... }
FORCE_INLINE_ATTR bool is_mxic_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == MXIC_ID;
}{ ... }
esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void)
{
uint16_t status = 0;
uint16_t new_status = 0;
uint8_t status_sr2 = 0;
uint8_t new_status_sr2 = 0;
uint8_t sr1_bit_num = 0;
esp_err_t err = ESP_OK;
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
if (is_issi_chip(&g_rom_flashchip) || is_mxic_chip(&g_rom_flashchip)) {
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
/* ... */
sr1_bit_num = 8;
new_status = status & (~ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI);
}{...} else if (is_gd_q_chip(&g_rom_flashchip)) {
/* ... */
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
sr1_bit_num = 8;
new_status = 0;
status_sr2 = bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8);
new_status_sr2 = status_sr2 & ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2;
}{...} else {
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
/* ... */
sr1_bit_num = 16;
new_status = status & ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE;
}{...}
bool status_written = false;
if (status != new_status) {
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
bootloader_execute_flash_command(CMD_WRSR, new_status, sr1_bit_num, 0);
status_written = true;
}{...}
if (status_sr2 != new_status_sr2) {
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
bootloader_execute_flash_command(CMD_WRSR2, new_status_sr2, 8, 0);
status_written = true;
}{...}
if (status_written) {
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);
}{...}
return err;
}{ ... }
IRAM_ATTR uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len)
{
assert(mosi_len <= 32);
assert(miso_len <= 32);
uint32_t old_ctrl_reg = 0;
uint32_t old_user_reg = 0;
uint32_t old_user1_reg = 0;
uint32_t old_user2_reg = 0;
spi_flash_ll_get_common_command_register_info(&SPIMEM_LL_APB, &old_ctrl_reg, &old_user_reg, &old_user1_reg, &old_user2_reg);
SPIMEM_LL_APB.ctrl.val = 0;
#if CONFIG_IDF_TARGET_ESP32
spi_flash_ll_set_wp_level(&SPIMEM_LL_APB, true);
#else
spimem_flash_ll_set_wp_level(&SPIMEM_LL_APB, true);
#endif
spi_flash_ll_set_command(&SPIMEM_LL_APB, command, 8);
spi_flash_ll_set_addr_bitlen(&SPIMEM_LL_APB, addr_len);
spi_flash_ll_set_usr_address(&SPIMEM_LL_APB, address, addr_len);
uint32_t total_dummy = dummy_len;
if (miso_len > 0) {
total_dummy += g_rom_spiflash_dummy_len_plus[1];
}{...}
spi_flash_ll_set_dummy(&SPIMEM_LL_APB, total_dummy);
spi_flash_ll_set_mosi_bitlen(&SPIMEM_LL_APB, mosi_len);
spi_flash_ll_set_buffer_data(&SPIMEM_LL_APB, &mosi_data, mosi_len / 8);
spi_flash_ll_set_miso_bitlen(&SPIMEM_LL_APB, miso_len);
spi_flash_ll_user_start(&SPIMEM_LL_APB, false);
while(!spi_flash_ll_cmd_is_done(&SPIMEM_LL_APB)) {
}{...}
spi_flash_ll_set_common_command_register_info(&SPIMEM_LL_APB, old_ctrl_reg, old_user_reg, old_user1_reg, old_user2_reg);
uint32_t output_data = 0;
spi_flash_ll_get_buffer_data(&SPIMEM_LL_APB, &output_data, miso_len / 8);
uint32_t ret = output_data;
if (miso_len < 32) {
ret &= ~(UINT32_MAX << miso_len);
}{...}
return ret;
}{ ... }
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{
const uint8_t addr_len = 0;
const uint8_t address = 0;
const uint8_t dummy_len = 0;
return bootloader_flash_execute_command_common(command, addr_len, address,
dummy_len, mosi_len, mosi_data, miso_len);
}{ ... }
uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
{
assert(miso_byte_num <= 4);
const uint8_t command = CMD_RDSFDP;
const uint8_t addr_len = 24;
const uint8_t dummy_len = 8;
const uint8_t mosi_len = 0;
const uint32_t mosi_data = 0;
const uint8_t miso_len = miso_byte_num * 8;
return bootloader_flash_execute_command_common(command, addr_len, sfdp_addr,
dummy_len, mosi_len, mosi_data, miso_len);
}{ ... }
void bootloader_enable_wp(void)
{
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);
}{ ... }
uint32_t IRAM_ATTR bootloader_read_flash_id(void)
{
uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
return id;
}{ ... }
void bootloader_spi_flash_reset(void)
{
bootloader_execute_flash_command(CMD_RESETEN, 0, 0, 0);
bootloader_execute_flash_command(CMD_RESET, 0, 0, 0);
}{ ... }
/* ... */
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
#define XMC_VENDOR_ID_1 0x20
#if BOOTLOADER_BUILD
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_EARLY_LOG##level(TAG, ##__VA_ARGS__)
#else
static DRAM_ATTR char bootloader_flash_tag[] = "bootloader_flash";
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_DRAM_LOG##level(bootloader_flash_tag, ##__VA_ARGS__)/* ... */
#endif
#if XMC_SUPPORT
static IRAM_ATTR bool is_xmc_chip_strict(uint32_t rdid)
{
uint32_t vendor_id = BYTESHIFT(rdid, 2);
uint32_t mfid = BYTESHIFT(rdid, 1);
uint32_t cpid = BYTESHIFT(rdid, 0);
if (vendor_id != XMC_VENDOR_ID_1) {
return false;
}{...}
bool matched = false;
if (mfid == 0x40) {
if (cpid >= 0x13 && cpid <= 0x20) {
matched = true;
}{...}
}{...} else if (mfid == 0x41) {
if (cpid >= 0x17 && cpid <= 0x20) {
matched = true;
}{...}
}{...} else if (mfid == 0x50) {
if (cpid >= 0x15 && cpid <= 0x16) {
matched = true;
}{...}
}{...}
return matched;
}{ ... }
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
{
const bool fast_check = true;
if (fast_check && is_xmc_chip_strict(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(D, "XMC chip detected by RDID (%08" PRIX32 "), skip.", g_rom_flashchip.device_id);
return ESP_OK;
}{...}
const int sfdp_mfid_addr = 0x10;
uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff);
if (mf_id != XMC_VENDOR_ID_1) {
BOOTLOADER_FLASH_LOG(D, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id);
return ESP_OK;
}{...}
BOOTLOADER_FLASH_LOG(I, "XM25QHxxC startup flow");
bootloader_execute_flash_command(0xB9, 0, 0, 0);
bootloader_execute_flash_command(0x79, 0, 0, 0);
bootloader_execute_flash_command(0xFF, 0, 0, 0);
esp_rom_delay_us(2000);
bootloader_execute_flash_command(0xAB, 0, 0, 0);
esp_rom_delay_us(20);
g_rom_flashchip.device_id = bootloader_read_flash_id();
if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(E, "XMC flash startup fail");
return ESP_FAIL;
}{...}
return ESP_OK;
}{ ... }
/* ... */#else
static IRAM_ATTR bool is_xmc_chip(uint32_t rdid)
{
uint32_t vendor_id = (rdid >> 16) & 0xFF;
return (vendor_id == XMC_VENDOR_ID_1);
}{...}
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
{
if (is_xmc_chip(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(E, "XMC chip detected (%08X) while support disabled.", g_rom_flashchip.device_id);
return ESP_FAIL;
}{...}
return ESP_OK;
}{...}
/* ... */
#endif
esp_err_t IRAM_ATTR bootloader_flash_reset_chip(void)
{
spi_flash_ll_sync_reset();
bootloader_execute_flash_command(0x05, 0, 0, 0);
#if CONFIG_IDF_TARGET_ESP32
if (SPI1.ext2.st != 0)
#else
if (!spimem_flash_ll_host_idle(&SPIMEM1))
#endif
{
return ESP_FAIL;
}{...}
bootloader_execute_flash_command(0x66, 0, 0, 0);
bootloader_execute_flash_command(0x99, 0, 0, 0);
return ESP_OK;
}{ ... }
bool IRAM_ATTR bootloader_flash_is_octal_mode_enabled(void)
{
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
return efuse_ll_get_flash_type();
#else
return false;
#endif
}{ ... }
esp_rom_spiflash_read_mode_t bootloader_flash_get_spi_mode(void)
{
esp_rom_spiflash_read_mode_t spi_mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
uint32_t spi_ctrl = spi_flash_ll_get_ctrl_val(&SPIMEM_LL_CACHE);
#if CONFIG_IDF_TARGET_ESP32
if (spi_ctrl & SPI_FREAD_QIO) {
spi_mode = ESP_ROM_SPIFLASH_QIO_MODE;
}{...} else if (spi_ctrl & SPI_FREAD_QUAD) {
spi_mode = ESP_ROM_SPIFLASH_QOUT_MODE;
}{...} else if (spi_ctrl & SPI_FREAD_DIO) {
spi_mode = ESP_ROM_SPIFLASH_DIO_MODE;
}{...} else if (spi_ctrl & SPI_FREAD_DUAL) {
spi_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
}{...} else if (spi_ctrl & SPI_FASTRD_MODE) {
spi_mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
}{...} else {
spi_mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
}{...}
#else/* ... */
if (spi_ctrl & SPI_MEM_FREAD_QIO) {
spi_mode = ESP_ROM_SPIFLASH_QIO_MODE;
}{...} else if (spi_ctrl & SPI_MEM_FREAD_QUAD) {
spi_mode = ESP_ROM_SPIFLASH_QOUT_MODE;
}{...} else if (spi_ctrl & SPI_MEM_FREAD_DIO) {
spi_mode = ESP_ROM_SPIFLASH_DIO_MODE;
}{...} else if (spi_ctrl & SPI_MEM_FREAD_DUAL) {
spi_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
}{...} else if (spi_ctrl & SPI_MEM_FASTRD_MODE) {
spi_mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
}{...} else {
spi_mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
}{...}
#endif/* ... */
return spi_mode;
}{ ... }