From 51584d4f2a907a5c6820b25f666eec3972775160 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 4 Mar 2022 17:35:00 +0800 Subject: [PATCH 1/8] spi_flash: partially move API functions out of IRAM --- components/spi_flash/esp_flash_api.c | 85 +++++++++++++++++++--------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index a5bf7141df..e92d96d314 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -502,7 +502,27 @@ esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_ return spiflash_end(chip, err); } -esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length) +static esp_err_t NOINLINE_ATTR IRAM_ATTR flash_read_core(esp_flash_t *chip, void* buffer_to_read, uint32_t address, uint32_t length_to_read, bool *out_read_success) +{ + esp_err_t err = ESP_OK; + bool read_success = false; + + read_success = false; + err = spiflash_start(chip); + + if (err == ESP_OK) { + err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read); + } + if (err == ESP_OK) { + read_success = true; + } + + err = spiflash_end(chip, err); + *out_read_success = read_success; + return err; +} + +esp_err_t esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length) { if (length == 0) { return ESP_OK; @@ -543,28 +563,17 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add esp_err_t err = ESP_OK; do { - err = spiflash_start(chip); - if (err != ESP_OK) { - break; - } //if required (dma buffer allocated), read to the buffer instead of the original buffer uint8_t* buffer_to_read = (temp_buffer)? temp_buffer : buffer; // Length we will read this iteration is either the chunk size or the remaining length, whichever is smaller size_t length_to_read = MIN(read_chunk_size, length); - if (err == ESP_OK) { - err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read); - } - if (err != ESP_OK) { - spiflash_end(chip, err); - break; - } - //even if this is failed, the data is still valid, copy before quit - err = spiflash_end(chip, err); + bool read_success; + err = flash_read_core(chip, buffer_to_read, address, length_to_read, &read_success); //copy back to the original buffer - if (temp_buffer) { + if (read_success && temp_buffer) { memcpy(buffer, temp_buffer, length_to_read); } address += length_to_read; @@ -576,7 +585,28 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add return err; } -esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +// This function disable the cache, but when returning from this function, the cache should be enabled. +static esp_err_t IRAM_ATTR NOINLINE_ATTR flash_write_core(esp_flash_t *chip, + const void* write_buf, uint32_t write_addr, uint32_t write_len, + uint32_t address, uint32_t length, bool final) +{ + bool bus_acquire = false; //controls whether the flash_end_flush_cache() needs to disable the cache again. + + esp_err_t err = spiflash_start(chip); + + if (err == ESP_OK) { + bus_acquire = true; + err = chip->chip_drv->write(chip, write_buf, write_addr, write_len); + } + + if (bus_acquire) { + //on IDF v4.2, the flush is done in chip driver layer. Call spiflash_end() here. + err = spiflash_end(chip, err); + } + return err; +} + +esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) { if (length == 0) { return ESP_OK; @@ -595,31 +625,32 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3 by artificially cutting into MAX_WRITE_CHUNK parts (in an OS environment, this prevents writing from causing interrupt or higher priority task starvation.) */ + uint32_t write_addr = address; + uint32_t len_remain = length; do { uint32_t write_len; const void *write_buf; uint32_t temp_buf[8]; if (direct_write) { - write_len = MIN(length, MAX_WRITE_CHUNK); + write_len = MIN(len_remain, MAX_WRITE_CHUNK); write_buf = buffer; } else { - write_len = MIN(length, sizeof(temp_buf)); + write_len = MIN(len_remain, sizeof(temp_buf)); memcpy(temp_buf, buffer, write_len); write_buf = temp_buf; } - err = spiflash_start(chip); - if (err != ESP_OK) { - return err; + bool final = (len_remain == write_len); + //This function ensures cache enabled when returned + err = flash_write_core(chip, write_buf, write_addr, write_len, address, length, final); + if (err != ESP_OK || final) { + break; } - err = chip->chip_drv->write(chip, write_buf, address, write_len); - - address += write_len; + len_remain -= write_len; + assert(len_remain < length); + write_addr += write_len; buffer = (void *)((intptr_t)buffer + write_len); - length -= write_len; - - err = spiflash_end(chip, err); } while (err == ESP_OK && length > 0); return err; } From a130dcd5ec2a813194b85b03c4bbbd8fb3ba3e6b Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sat, 21 May 2022 15:47:18 +0800 Subject: [PATCH 2/8] test_spiffs: increase test case stack size --- components/spiffs/test/test_spiffs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/spiffs/test/test_spiffs.c b/components/spiffs/test/test_spiffs.c index 34a2de8745..c824154d25 100644 --- a/components/spiffs/test/test_spiffs.c +++ b/components/spiffs/test/test_spiffs.c @@ -394,6 +394,8 @@ done: void test_spiffs_concurrent(const char* filename_prefix) { + const int stack_size=3072; + char names[4][64]; for (size_t i = 0; i < 4; ++i) { snprintf(names[i], sizeof(names[i]), "%s%d", filename_prefix, i + 1); @@ -406,8 +408,8 @@ void test_spiffs_concurrent(const char* filename_prefix) printf("writing f1 and f2\n"); const int cpuid_0 = 0; const int cpuid_1 = portNUM_PROCESSORS - 1; - xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, cpuid_0); - xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, cpuid_1); + xTaskCreatePinnedToCore(&read_write_task, "rw1", stack_size, &args1, 3, NULL, cpuid_0); + xTaskCreatePinnedToCore(&read_write_task, "rw2", stack_size, &args2, 3, NULL, cpuid_1); xSemaphoreTake(args1.done, portMAX_DELAY); printf("f1 done\n"); @@ -423,10 +425,10 @@ void test_spiffs_concurrent(const char* filename_prefix) printf("reading f1 and f2, writing f3 and f4\n"); - xTaskCreatePinnedToCore(&read_write_task, "rw3", 2048, &args3, 3, NULL, cpuid_1); - xTaskCreatePinnedToCore(&read_write_task, "rw4", 2048, &args4, 3, NULL, cpuid_0); - xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, cpuid_0); - xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, cpuid_1); + xTaskCreatePinnedToCore(&read_write_task, "rw3", stack_size, &args3, 3, NULL, cpuid_1); + xTaskCreatePinnedToCore(&read_write_task, "rw4", stack_size, &args4, 3, NULL, cpuid_0); + xTaskCreatePinnedToCore(&read_write_task, "rw1", stack_size, &args1, 3, NULL, cpuid_0); + xTaskCreatePinnedToCore(&read_write_task, "rw2", stack_size, &args2, 3, NULL, cpuid_1); xSemaphoreTake(args1.done, portMAX_DELAY); printf("f1 done\n"); From 9582cbe5b8436eeacec11c66321c29f93be4532e Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 12 Mar 2020 18:20:31 +0800 Subject: [PATCH 3/8] bootloader: fix the WRSR format for ISSI flash chips 1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability. This commit helps to clear WEL when flash configuration is done. **RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA. 2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips. Status register bitmap of ISSI chip and GD chip: | SR | ISSI | GD25LQ32C | | -- | ---- | --------- | | 0 | WIP | WIP | | 1 | WEL | WEL | | 2 | BP0 | BP0 | | 3 | BP1 | BP1 | | 4 | BP2 | BP2 | | 5 | BP3 | BP3 | | 6 | QE | BP4 | | 7 | SRWD | SRP0 | | 8 | | SRP1 | | 9 | | QE | | 10 | | SUS2 | | 11 | | LB1 | | 12 | | LB2 | | 13 | | LB3 | | 14 | | CMP | | 15 | | SUS1 | QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command. However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips. Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected. This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6). 3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared. This commit skips the clearing of status register if there is no protection bits active. Also move the execute_flash_command to be a bootloader API; move implementation of spi_flash_wrap_set to the bootloader --- .../include_bootloader/bootloader_flash.h | 41 +++++ .../bootloader_support/src/bootloader_flash.c | 106 ++++++++++++- .../src/esp32/bootloader_esp32.c | 3 + .../src/esp32s2/bootloader_esp32s2.c | 3 + .../bootloader_support/src/flash_qio_mode.c | 142 +++--------------- .../esp_rom/include/esp32/rom/spi_flash.h | 1 + .../esp_rom/include/esp32s2/rom/opi_flash.h | 1 + .../esp_rom/include/esp32s2/rom/spi_flash.h | 1 + .../soc/soc/esp32s2/include/soc/soc_caps.h | 2 + components/spi_flash/CMakeLists.txt | 3 +- components/spi_flash/Kconfig | 5 +- .../spi_flash/esp32/spi_flash_rom_patch.c | 42 ++++-- .../spi_flash/esp32s2/flash_ops_esp32s2.c | 39 +---- components/spi_flash/flash_ops.c | 3 +- 14 files changed, 218 insertions(+), 174 deletions(-) diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash.h index 6482dde99e..e2e0f3ed65 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash.h @@ -19,11 +19,26 @@ #include #include #include /* including in bootloader for error values */ +#include "sdkconfig.h" #define FLASH_SECTOR_SIZE 0x1000 #define FLASH_BLOCK_SIZE 0x10000 #define MMAP_ALIGNED_MASK 0x0000FFFF +/* SPI commands (actual on-wire commands not SPI controller bitmasks) + Suitable for use with the bootloader_execute_flash_command static function. +*/ +#define CMD_RDID 0x9F +#define CMD_WRSR 0x01 +#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ +#define CMD_WREN 0x06 +#define CMD_WRDI 0x04 +#define CMD_RDSR 0x05 +#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ +#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */ +#define CMD_WRAP 0x77 /* Set burst with wrap command */ + + /* Provide a Flash API for bootloader_support code, that can be used from bootloader or app code. @@ -136,4 +151,30 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) / MMU_BLOCK_SIZE; } +/** + * @brief Execute a user command on the flash + * + * @param command The command value to execute. + * @param mosi_data MOSI data to send + * @param mosi_len Length of MOSI data, in bits + * @param miso_len Length of MISO data to receive, in bits + * @return Received MISO data + */ +uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); + +/** + * @brief Enable the flash write protect (WEL bit). + */ +void bootloader_enable_wp(void); + +#if CONFIG_IDF_TARGET_ESP32S2 +/** + * @brief Set the burst mode setting command for specified wrap mode. + * + * @param mode The specified warp mode. + * @return always ESP_OK + */ +esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode); +#endif + #endif diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 9aadb8fc14..6716e3bc53 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -16,10 +16,26 @@ #include #include #include -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/spi_flash.h" +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +#if CONFIG_IDF_TARGET_ESP32 +# include "soc/spi_struct.h" +# include "soc/spi_reg.h" + /* SPI flash controller */ +# define SPIFLASH SPI1 +#else +# include "soc/spi_mem_struct.h" +# include "soc/spi_mem_reg.h" + /* SPI flash controller */ +# define SPIFLASH SPIMEM1 #endif +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/spi_flash.h" //For SPI_Encrypt_Write +#endif + + #ifndef BOOTLOADER_BUILD /* Normal app version maps to esp_spi_flash.h operations... */ @@ -364,4 +380,90 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) } return spi_to_esp_err(rc); } + #endif + +extern uint8_t g_rom_spiflash_dummy_len_plus[]; +uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) +{ + uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; +#if CONFIG_IDF_TARGET_ESP32 + SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode +#endif + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user.usr_addr = 0; + SPIFLASH.user.usr_command = 1; + SPIFLASH.user2.usr_command_bitlen = 7; + + SPIFLASH.user2.usr_command_value = command; + SPIFLASH.user.usr_miso = miso_len > 0; +#if CONFIG_IDF_TARGET_ESP32 + SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0; +#endif + SPIFLASH.user.usr_mosi = mosi_len > 0; +#if CONFIG_IDF_TARGET_ESP32 + SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0; +#endif + SPIFLASH.data_buf[0] = mosi_data; + + if (g_rom_spiflash_dummy_len_plus[1]) { + /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ + if (miso_len > 0) { + SPIFLASH.user.usr_dummy = 1; + SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1; + } else { + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user1.usr_dummy_cyclelen = 0; + } + } + + SPIFLASH.cmd.usr = 1; + while (SPIFLASH.cmd.usr != 0) { + } + + SPIFLASH.ctrl.val = old_ctrl_reg; + return SPIFLASH.data_buf[0]; +} + +void bootloader_enable_wp(void) +{ + bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */ +} + +#if SOC_CACHE_SUPPORT_WRAP +esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode) +{ + uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val; + uint32_t reg_bkp_usr = SPIFLASH.user.val; + SPIFLASH.user.fwrite_dio = 0; + SPIFLASH.user.fwrite_dual = 0; + SPIFLASH.user.fwrite_qio = 1; + SPIFLASH.user.fwrite_quad = 0; + SPIFLASH.ctrl.fcmd_dual = 0; + SPIFLASH.ctrl.fcmd_quad = 0; + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user.usr_addr = 1; + SPIFLASH.user.usr_command = 1; + SPIFLASH.user2.usr_command_bitlen = 7; + SPIFLASH.user2.usr_command_value = CMD_WRAP; + SPIFLASH.user1.usr_addr_bitlen = 23; + SPIFLASH.addr = 0; + SPIFLASH.user.usr_miso = 0; + SPIFLASH.user.usr_mosi = 1; + SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7; + SPIFLASH.data_buf[0] = (uint32_t) mode << 4;; + SPIFLASH.cmd.usr = 1; + while(SPIFLASH.cmd.usr != 0) + { } + + SPIFLASH.ctrl.val = reg_bkp_ctrl; + SPIFLASH.user.val = reg_bkp_usr; + return ESP_OK; +} +#endif //SOC_CACHE_SUPPORT_WRAP \ No newline at end of file diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 19d712dd3f..0dbf9f8749 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -23,6 +23,7 @@ #include "bootloader_common.h" #include "bootloader_flash_config.h" #include "bootloader_mem.h" +#include "bootloader_flash.h" #include "soc/cpu.h" #include "soc/dport_reg.h" @@ -267,6 +268,8 @@ static esp_err_t bootloader_init_spi_flash(void) print_flash_info(&bootloader_image_hdr); update_flash_config(&bootloader_image_hdr); + //ensure the flash is write-protected + bootloader_enable_wp(); return ESP_OK; } diff --git a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c index 050d0afda5..0bddc3ff2f 100644 --- a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c +++ b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c @@ -26,6 +26,7 @@ #include "bootloader_clock.h" #include "bootloader_flash_config.h" #include "bootloader_mem.h" +#include "bootloader_flash.h" #include "esp32s2/rom/cache.h" #include "esp32s2/rom/ets_sys.h" @@ -213,6 +214,8 @@ static esp_err_t bootloader_init_spi_flash(void) print_flash_info(&bootloader_image_hdr); update_flash_config(&bootloader_image_hdr); + //ensure the flash is write-protected + bootloader_enable_wp(); return ESP_OK; } diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index e08824b932..b415de57d7 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -15,6 +15,7 @@ #include #include "bootloader_flash_config.h" #include "flash_qio_mode.h" +#include "bootloader_flash.h" #include "esp_log.h" #include "esp_err.h" #if CONFIG_IDF_TARGET_ESP32 @@ -25,30 +26,10 @@ #include "esp32s2/rom/efuse.h" #include "soc/spi_mem_struct.h" #endif -#include "soc/spi_struct.h" -#include "soc/spi_reg.h" #include "soc/efuse_periph.h" #include "soc/io_mux_reg.h" #include "sdkconfig.h" -/* SPI flash controller */ -#if CONFIG_IDF_TARGET_ESP32 -#define SPIFLASH SPI1 -#elif CONFIG_IDF_TARGET_ESP32S2 -#define SPIFLASH SPIMEM1 -#endif - -/* SPI commands (actual on-wire commands not SPI controller bitmasks) - Suitable for use with the execute_flash_command static function. -*/ -#define CMD_RDID 0x9F -#define CMD_WRSR 0x01 -#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ -#define CMD_WREN 0x06 -#define CMD_WRDI 0x04 -#define CMD_RDSR 0x05 -#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ -#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */ static const char *TAG = "qio_mode"; @@ -126,57 +107,15 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn, The command passed here is always the on-the-wire command given to the SPI flash unit. */ -static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); /* dummy_len_plus values defined in ROM for SPI flash configuration */ -extern uint8_t g_rom_spiflash_dummy_len_plus[]; uint32_t bootloader_read_flash_id(void) { - uint32_t id = execute_flash_command(CMD_RDID, 0, 0, 24); + uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24); id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); return id; } -#if CONFIG_IDF_TARGET_ESP32S2 -#define FLASH_WRAP_CMD 0x77 -typedef enum { - FLASH_WRAP_MODE_8B = 0, - FLASH_WRAP_MODE_16B = 2, - FLASH_WRAP_MODE_32B = 4, - FLASH_WRAP_MODE_64B = 6, - FLASH_WRAP_MODE_DISABLE = 1 -} spi_flash_wrap_mode_t; -static esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode) -{ - uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val; - uint32_t reg_bkp_usr = SPIFLASH.user.val; - SPIFLASH.user.fwrite_dio = 0; - SPIFLASH.user.fwrite_dual = 0; - SPIFLASH.user.fwrite_qio = 1; - SPIFLASH.user.fwrite_quad = 0; - SPIFLASH.ctrl.fcmd_dual = 0; - SPIFLASH.ctrl.fcmd_quad = 0; - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user.usr_addr = 1; - SPIFLASH.user.usr_command = 1; - SPIFLASH.user2.usr_command_bitlen = 7; - SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD; - SPIFLASH.user1.usr_addr_bitlen = 23; - SPIFLASH.addr = 0; - SPIFLASH.user.usr_miso = 0; - SPIFLASH.user.usr_mosi = 1; - SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7; - SPIFLASH.data_buf[0] = (uint32_t) mode << 4;; - SPIFLASH.cmd.usr = 1; - while (SPIFLASH.cmd.usr != 0) { - } - - SPIFLASH.ctrl.val = reg_bkp_ctrl; - SPIFLASH.user.val = reg_bkp_usr; - return ESP_OK; -} -#endif - void bootloader_enable_qio_mode(void) { uint32_t raw_flash_id; @@ -208,8 +147,8 @@ void bootloader_enable_qio_mode(void) enable_qio_mode(chip_data[i].read_status_fn, chip_data[i].write_status_fn, chip_data[i].status_qio_bit); -#if CONFIG_IDF_TARGET_ESP32S2 - spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); +#if SOC_CACHE_SUPPORT_WRAP + bootloader_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); #endif } @@ -226,7 +165,7 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn, ESP_LOGD(TAG, "Initial flash chip status 0x%x", status); if ((status & (1 << status_qio_bit)) == 0) { - execute_flash_command(CMD_WREN, 0, 0, 0); + bootloader_execute_flash_command(CMD_WREN, 0, 0, 0); write_status_fn(status | (1 << status_qio_bit)); esp_rom_spiflash_wait_idle(&g_rom_flashchip); @@ -264,95 +203,48 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn, static unsigned read_status_8b_rdsr(void) { - return execute_flash_command(CMD_RDSR, 0, 0, 8); + return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8); } static unsigned read_status_8b_rdsr2(void) { - return execute_flash_command(CMD_RDSR2, 0, 0, 8); + return bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8); } static unsigned read_status_16b_rdsr_rdsr2(void) { - return execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8); + return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8); } static void write_status_8b_wrsr(unsigned new_status) { - execute_flash_command(CMD_WRSR, new_status, 8, 0); + bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0); } static void write_status_8b_wrsr2(unsigned new_status) { - execute_flash_command(CMD_WRSR2, new_status, 8, 0); + bootloader_execute_flash_command(CMD_WRSR2, new_status, 8, 0); } static void write_status_16b_wrsr(unsigned new_status) { - execute_flash_command(CMD_WRSR, new_status, 16, 0); + bootloader_execute_flash_command(CMD_WRSR, new_status, 16, 0); } static unsigned read_status_8b_xmc25qu64a(void) { - execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ + bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); - uint32_t read_status = execute_flash_command(CMD_RDSR, 0, 0, 8); - execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */ + uint32_t read_status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8); + bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */ return read_status; } static void write_status_8b_xmc25qu64a(unsigned new_status) { - execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ + bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); - execute_flash_command(CMD_WRSR, new_status, 8, 0); + bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0); esp_rom_spiflash_wait_idle(&g_rom_flashchip); - execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */ -} - -static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) -{ - uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; -#if CONFIG_IDF_TARGET_ESP32 - SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode -#elif CONFIG_IDF_TARGET_ESP32S2 - SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode -#endif - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user.usr_addr = 0; - SPIFLASH.user.usr_command = 1; - SPIFLASH.user2.usr_command_bitlen = 7; - - SPIFLASH.user2.usr_command_value = command; - SPIFLASH.user.usr_miso = miso_len > 0; -#if CONFIG_IDF_TARGET_ESP32 - SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; -#elif CONFIG_IDF_TARGET_ESP32S2 - SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0; -#endif - SPIFLASH.user.usr_mosi = mosi_len > 0; -#if CONFIG_IDF_TARGET_ESP32 - SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; -#elif CONFIG_IDF_TARGET_ESP32S2 - SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0; -#endif - SPIFLASH.data_buf[0] = mosi_data; - - if (g_rom_spiflash_dummy_len_plus[1]) { - /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ - if (miso_len > 0) { - SPIFLASH.user.usr_dummy = 1; - SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1; - } else { - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user1.usr_dummy_cyclelen = 0; - } - } - - SPIFLASH.cmd.usr = 1; - while (SPIFLASH.cmd.usr != 0) { - } - - SPIFLASH.ctrl.val = old_ctrl_reg; - return SPIFLASH.data_buf[0]; + bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */ } diff --git a/components/esp_rom/include/esp32/rom/spi_flash.h b/components/esp_rom/include/esp32/rom/spi_flash.h index f4b17ae5be..6174f05e73 100644 --- a/components/esp_rom/include/esp32/rom/spi_flash.h +++ b/components/esp_rom/include/esp32/rom/spi_flash.h @@ -121,6 +121,7 @@ extern "C" { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 +#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2) //Extra dummy for flash read #define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0 diff --git a/components/esp_rom/include/esp32s2/rom/opi_flash.h b/components/esp_rom/include/esp32s2/rom/opi_flash.h index bb209f67f0..c985810b67 100644 --- a/components/esp_rom/include/esp32s2/rom/opi_flash.h +++ b/components/esp_rom/include/esp32s2/rom/opi_flash.h @@ -40,6 +40,7 @@ typedef struct { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 +#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2) #define FLASH_OP_MODE_RDCMD_DOUT 0x3B #define ESP_ROM_FLASH_SECTOR_SIZE 0x1000 diff --git a/components/esp_rom/include/esp32s2/rom/spi_flash.h b/components/esp_rom/include/esp32s2/rom/spi_flash.h index 1eee20a5fa..2cf631666c 100644 --- a/components/esp_rom/include/esp32s2/rom/spi_flash.h +++ b/components/esp_rom/include/esp32s2/rom/spi_flash.h @@ -119,6 +119,7 @@ extern "C" { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 +#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2) #define FLASH_ID_GD25LQ32C 0xC86016 diff --git a/components/soc/soc/esp32s2/include/soc/soc_caps.h b/components/soc/soc/esp32s2/include/soc/soc_caps.h index 565409cda1..95d5e98c0f 100644 --- a/components/soc/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/soc/esp32s2/include/soc/soc_caps.h @@ -9,6 +9,8 @@ #define SOC_CPU_CORES_NUM 1 #define SOC_SUPPORTS_SECURE_DL_MODE 1 +#define SOC_CACHE_SUPPORT_WRAP 1 + /*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/ #define SOC_PHY_DIG_REGS_MEM_SIZE (21*4) diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 2e2d6e6a4b..a9b99a2d56 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -1,5 +1,3 @@ -set(priv_requires bootloader_support soc) - if(BOOTLOADER_BUILD) if (CONFIG_IDF_TARGET_ESP32) # ESP32 Bootloader needs SPIUnlock from this file, but doesn't @@ -10,6 +8,7 @@ if(BOOTLOADER_BUILD) set(srcs) endif() set(cache_srcs "") + set(priv_requires bootloader_support soc) else() set(cache_srcs "cache_utils.c" diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index aef596d621..3faafa1cca 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -49,8 +49,9 @@ menu "SPI Flash driver" default y help Enable this flag to use patched versions of SPI flash ROM driver functions. - This option is needed to write to flash on ESP32-D2WD, and any configuration - where external SPI flash is connected to non-default pins. + This option should be enabled, if any one of the following is true: (1) need to write + to flash on ESP32-D2WD; (2) main SPI flash is connected to non-default pins; (3) main + SPI flash chip is manufactured by ISSI. choice SPI_FLASH_DANGEROUS_WRITE bool "Writing to dangerous flash regions" diff --git a/components/spi_flash/esp32/spi_flash_rom_patch.c b/components/spi_flash/esp32/spi_flash_rom_patch.c index ec1ade5385..6aa469686a 100644 --- a/components/spi_flash/esp32/spi_flash_rom_patch.c +++ b/components/spi_flash/esp32/spi_flash_rom_patch.c @@ -21,8 +21,14 @@ #define SPI_IDX 1 #define OTH_IDX 0 + extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; +static inline bool is_issi_chip(const esp_rom_spiflash_chip_t* chip) +{ + return (((chip->device_id >> 16)&0xff) == 0x9D); +} + esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi) { uint32_t status; @@ -61,25 +67,43 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void) { uint32_t status; + uint32_t new_status; esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); - if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { - return ESP_ROM_SPIFLASH_RESULT_ERR; - } + if (is_issi_chip(&g_rom_spiflash_chip)) { + // ISSI chips have different QE position - /* Clear all bits except QIE, if it is set. - (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) - */ - status &= ESP_ROM_SPIFLASH_QE; + if (esp_rom_spiflash_read_status(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + /* Clear all bits in the mask. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + new_status = status & (~ESP_ROM_SPIFLASH_BP_MASK_ISSI); + // Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing. + if (new_status == status) return ESP_ROM_SPIFLASH_RESULT_OK; + + CLEAR_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + } else { + if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + /* Clear all bits except QE, if it is set. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + new_status = status & ESP_ROM_SPIFLASH_QE; + SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + } esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { } esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); - SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); - if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, status) != ESP_ROM_SPIFLASH_RESULT_OK) { + if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, new_status) != ESP_ROM_SPIFLASH_RESULT_OK) { return ESP_ROM_SPIFLASH_RESULT_ERR; } diff --git a/components/spi_flash/esp32s2/flash_ops_esp32s2.c b/components/spi_flash/esp32s2/flash_ops_esp32s2.c index 039845ba46..ccdf0636c5 100644 --- a/components/spi_flash/esp32s2/flash_ops_esp32s2.c +++ b/components/spi_flash/esp32s2/flash_ops_esp32s2.c @@ -20,6 +20,7 @@ #include "soc/soc_memory_layout.h" #include "esp32s2/rom/spi_flash.h" #include "esp32s2/rom/cache.h" +#include "bootloader_flash.h" #include "hal/spi_flash_hal.h" #include "esp_flash.h" #include "esp_log.h" @@ -78,48 +79,22 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a } } -#define FLASH_WRAP_CMD 0x77 esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode) { - uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val; - uint32_t reg_bkp_usr = SPIFLASH.user.val; - SPIFLASH.user.fwrite_dio = 0; - SPIFLASH.user.fwrite_dual = 0; - SPIFLASH.user.fwrite_qio = 1; - SPIFLASH.user.fwrite_quad = 0; - SPIFLASH.ctrl.fcmd_dual = 0; - SPIFLASH.ctrl.fcmd_quad = 0; - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user.usr_addr = 1; - SPIFLASH.user.usr_command = 1; - SPIFLASH.user2.usr_command_bitlen = 7; - SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD; - SPIFLASH.user1.usr_addr_bitlen = 23; - SPIFLASH.addr = 0; - SPIFLASH.user.usr_miso = 0; - SPIFLASH.user.usr_mosi = 1; - SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7; - SPIFLASH.data_buf[0] = (uint32_t) mode << 4;; - SPIFLASH.cmd.usr = 1; - while(SPIFLASH.cmd.usr != 0) - { } - - SPIFLASH.ctrl.val = reg_bkp_ctrl; - SPIFLASH.user.val = reg_bkp_usr; - return ESP_OK; + return bootloader_flash_wrap_set(mode); } esp_err_t spi_flash_enable_wrap(uint32_t wrap_size) { switch(wrap_size) { case 8: - return spi_flash_wrap_set(FLASH_WRAP_MODE_8B); + return bootloader_flash_wrap_set(FLASH_WRAP_MODE_8B); case 16: - return spi_flash_wrap_set(FLASH_WRAP_MODE_16B); + return bootloader_flash_wrap_set(FLASH_WRAP_MODE_16B); case 32: - return spi_flash_wrap_set(FLASH_WRAP_MODE_32B); + return bootloader_flash_wrap_set(FLASH_WRAP_MODE_32B); case 64: - return spi_flash_wrap_set(FLASH_WRAP_MODE_64B); + return bootloader_flash_wrap_set(FLASH_WRAP_MODE_64B); default: return ESP_FAIL; } @@ -127,7 +102,7 @@ esp_err_t spi_flash_enable_wrap(uint32_t wrap_size) void spi_flash_disable_wrap(void) { - spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); + bootloader_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); } bool spi_flash_support_wrap_size(uint32_t wrap_size) diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index f6fc2443bf..7372d1c124 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -36,8 +36,6 @@ #include "esp32s2/rom/spi_flash.h" #include "esp32s2/rom/cache.h" #include "esp32s2/clk.h" -#include "soc/spi_mem_reg.h" -#include "soc/spi_mem_struct.h" #endif #include "esp_flash_partitions.h" #include "cache_utils.h" @@ -833,6 +831,7 @@ void spi_flash_dump_counters(void) #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS + #if defined(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) && defined(CONFIG_IDF_TARGET_ESP32S2) // TODO esp32s2: Remove once ESP32S2 has new SPI Flash API support esp_flash_t *esp_flash_default_chip = NULL; From e1bd7b9d8fd23f19006ec4c68074973a3f0926cc Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Mon, 13 Jul 2020 03:23:12 +0800 Subject: [PATCH 4/8] bootloader: create public bootloader_flash.h header Move non-public functions into bootloader_flash_priv.h header --- components/app_update/test/test_switch_ota.c | 2 +- .../include/bootloader_flash.h | 30 +++++++++++++++++++ ...loader_flash.h => bootloader_flash_priv.h} | 9 +----- .../src/bootloader_common.c | 2 +- .../bootloader_support/src/bootloader_flash.c | 2 +- .../bootloader_support/src/bootloader_init.c | 2 +- .../src/bootloader_utility.c | 2 +- .../src/esp32/bootloader_esp32.c | 2 +- .../src/esp32/flash_encrypt.c | 2 +- .../src/esp32/secure_boot.c | 2 +- .../src/esp32/secure_boot_signatures.c | 2 +- .../src/esp32s2/bootloader_esp32s2.c | 2 +- .../src/esp32s2/flash_encrypt.c | 6 ++-- .../src/esp32s2/secure_boot.c | 2 +- .../src/esp32s2/secure_boot_signatures.c | 2 +- .../bootloader_support/src/esp_image_format.c | 2 +- .../bootloader_support/src/flash_qio_mode.c | 2 +- .../src/idf/bootloader_sha.c | 2 +- .../src/idf/secure_boot_signatures.c | 4 +-- components/efuse/src/esp_efuse_fields.c | 2 +- 20 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 components/bootloader_support/include/bootloader_flash.h rename components/bootloader_support/include_bootloader/{bootloader_flash.h => bootloader_flash_priv.h} (95%) diff --git a/components/app_update/test/test_switch_ota.c b/components/app_update/test/test_switch_ota.c index 93e75a1308..e0fff8500e 100644 --- a/components/app_update/test/test_switch_ota.c +++ b/components/app_update/test/test_switch_ota.c @@ -23,7 +23,7 @@ #include "unity.h" #include "bootloader_common.h" -#include "../include_bootloader/bootloader_flash.h" +#include "../include_bootloader/bootloader_flash_priv.h" #include "esp_log.h" #include "esp_ota_ops.h" diff --git a/components/bootloader_support/include/bootloader_flash.h b/components/bootloader_support/include/bootloader_flash.h new file mode 100644 index 0000000000..5b74596544 --- /dev/null +++ b/components/bootloader_support/include/bootloader_flash.h @@ -0,0 +1,30 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include /* including in bootloader for error values */ +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +#if SOC_CACHE_SUPPORT_WRAP +/** + * @brief Set the burst mode setting command for specified wrap mode. + * + * @param mode The specified warp mode. + * @return always ESP_OK + */ +esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode); +#endif + diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash_priv.h similarity index 95% rename from components/bootloader_support/include_bootloader/bootloader_flash.h rename to components/bootloader_support/include_bootloader/bootloader_flash_priv.h index e2e0f3ed65..0f23f022c4 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash_priv.h @@ -20,6 +20,7 @@ #include #include /* including in bootloader for error values */ #include "sdkconfig.h" +#include "bootloader_flash.h" #define FLASH_SECTOR_SIZE 0x1000 #define FLASH_BLOCK_SIZE 0x10000 @@ -167,14 +168,6 @@ uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, u */ void bootloader_enable_wp(void); -#if CONFIG_IDF_TARGET_ESP32S2 -/** - * @brief Set the burst mode setting command for specified wrap mode. - * - * @param mode The specified warp mode. - * @return always ESP_OK - */ -esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode); #endif #endif diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index df86afe612..2f65752158 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -28,7 +28,7 @@ #include "esp32s2/rom/gpio.h" #endif #include "esp_flash_partitions.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_common.h" #include "bootloader_utility.h" #include "soc/gpio_periph.h" diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 6716e3bc53..d91c1cb4f3 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -13,7 +13,7 @@ // limitations under the License. #include -#include +#include #include #include #include "sdkconfig.h" diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 4c57e848ea..fb86e50dd8 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -17,7 +17,7 @@ #include "esp_attr.h" #include "esp_log.h" #include "bootloader_init.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_flash_config.h" #include "bootloader_random.h" #include "bootloader_clock.h" diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index c1209c2686..fcdac80119 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -59,7 +59,7 @@ #include "esp_secure_boot.h" #include "esp_flash_encrypt.h" #include "esp_flash_partitions.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_random.h" #include "bootloader_config.h" #include "bootloader_common.h" diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 0dbf9f8749..4b94e5c06a 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -23,7 +23,7 @@ #include "bootloader_common.h" #include "bootloader_flash_config.h" #include "bootloader_mem.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "soc/cpu.h" #include "soc/dport_reg.h" diff --git a/components/bootloader_support/src/esp32/flash_encrypt.c b/components/bootloader_support/src/esp32/flash_encrypt.c index 1346b882a2..ebbf598ea2 100644 --- a/components/bootloader_support/src/esp32/flash_encrypt.c +++ b/components/bootloader_support/src/esp32/flash_encrypt.c @@ -14,7 +14,7 @@ #include -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "esp_image_format.h" #include "esp_flash_encrypt.h" #include "esp_flash_partitions.h" diff --git a/components/bootloader_support/src/esp32/secure_boot.c b/components/bootloader_support/src/esp32/secure_boot.c index b223c868f7..88915e7e2d 100644 --- a/components/bootloader_support/src/esp32/secure_boot.c +++ b/components/bootloader_support/src/esp32/secure_boot.c @@ -29,7 +29,7 @@ #include "sdkconfig.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_random.h" #include "esp_image_format.h" #include "esp_secure_boot.h" diff --git a/components/bootloader_support/src/esp32/secure_boot_signatures.c b/components/bootloader_support/src/esp32/secure_boot_signatures.c index 1ff4999b85..e38e98201b 100644 --- a/components/bootloader_support/src/esp32/secure_boot_signatures.c +++ b/components/bootloader_support/src/esp32/secure_boot_signatures.c @@ -13,7 +13,7 @@ // limitations under the License. #include "sdkconfig.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_sha.h" #include "bootloader_utility.h" #include "esp_log.h" diff --git a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c index 0bddc3ff2f..7508f4f322 100644 --- a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c +++ b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c @@ -26,7 +26,7 @@ #include "bootloader_clock.h" #include "bootloader_flash_config.h" #include "bootloader_mem.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "esp32s2/rom/cache.h" #include "esp32s2/rom/ets_sys.h" diff --git a/components/bootloader_support/src/esp32s2/flash_encrypt.c b/components/bootloader_support/src/esp32s2/flash_encrypt.c index acc6b747e7..64af92eb71 100644 --- a/components/bootloader_support/src/esp32s2/flash_encrypt.c +++ b/components/bootloader_support/src/esp32s2/flash_encrypt.c @@ -14,7 +14,7 @@ #include -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_random.h" #include "bootloader_utility.h" #include "esp_image_format.h" @@ -303,8 +303,8 @@ static esp_err_t encrypt_bootloader(void) if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err); return err; - } - + } + ESP_LOGI(TAG, "bootloader encrypted successfully"); return err; } diff --git a/components/bootloader_support/src/esp32s2/secure_boot.c b/components/bootloader_support/src/esp32s2/secure_boot.c index b754a02aa5..82c908f8a7 100644 --- a/components/bootloader_support/src/esp32s2/secure_boot.c +++ b/components/bootloader_support/src/esp32s2/secure_boot.c @@ -17,7 +17,7 @@ #include "esp_secure_boot.h" #include "soc/efuse_reg.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_sha.h" #include "bootloader_utility.h" diff --git a/components/bootloader_support/src/esp32s2/secure_boot_signatures.c b/components/bootloader_support/src/esp32s2/secure_boot_signatures.c index e60fcacaf1..3da88b262c 100644 --- a/components/bootloader_support/src/esp32s2/secure_boot_signatures.c +++ b/components/bootloader_support/src/esp32s2/secure_boot_signatures.c @@ -15,7 +15,7 @@ #include #include "esp_fault.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_sha.h" #include "bootloader_utility.h" #include "esp_log.h" diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 84558225a9..8927c87501 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include "bootloader_util.h" diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index b415de57d7..83d5c5ef5f 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -15,7 +15,7 @@ #include #include "bootloader_flash_config.h" #include "flash_qio_mode.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "esp_log.h" #include "esp_err.h" #if CONFIG_IDF_TARGET_ESP32 diff --git a/components/bootloader_support/src/idf/bootloader_sha.c b/components/bootloader_support/src/idf/bootloader_sha.c index 8d70406c72..40308b667f 100644 --- a/components/bootloader_support/src/idf/bootloader_sha.c +++ b/components/bootloader_support/src/idf/bootloader_sha.c @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include "bootloader_sha.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include #include #include diff --git a/components/bootloader_support/src/idf/secure_boot_signatures.c b/components/bootloader_support/src/idf/secure_boot_signatures.c index 290f69848d..77cd29c3c2 100644 --- a/components/bootloader_support/src/idf/secure_boot_signatures.c +++ b/components/bootloader_support/src/idf/secure_boot_signatures.c @@ -13,7 +13,7 @@ // limitations under the License. #include "sdkconfig.h" -#include "bootloader_flash.h" +#include "bootloader_flash_priv.h" #include "bootloader_sha.h" #include "bootloader_utility.h" #include "esp_log.h" @@ -325,7 +325,7 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa break; } } - + free(sig_be); free(buf); #if CONFIG_IDF_TARGET_ESP32 diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index d6b36fd728..c28daca03d 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -48,7 +48,7 @@ void esp_efuse_reset(void) #ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE -#include "../include_bootloader/bootloader_flash.h" +#include "../include_bootloader/bootloader_flash_priv.h" #include "esp_flash_encrypt.h" static uint32_t esp_efuse_flash_offset = 0; From 33a8c60b2cf3fc7933cd0786d9a11a77a6c4eb1a Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sun, 1 Aug 2021 14:23:36 +0800 Subject: [PATCH 5/8] bootloader: add xmc spi_flash startup flow to improve reliability --- components/bootloader/Kconfig.projbuild | 9 + .../include/bootloader_flash.h | 23 ++ .../bootloader_flash_priv.h | 12 +- .../include_bootloader/flash_qio_mode.h | 2 + .../bootloader_support/src/bootloader_flash.c | 207 +++++++++++++++--- .../src/esp32/bootloader_esp32.c | 5 + .../src/esp32s2/bootloader_esp32s2.c | 5 + .../bootloader_support/src/flash_qio_mode.c | 8 - components/spi_flash/test/test_spi_flash.c | 21 ++ 9 files changed, 256 insertions(+), 36 deletions(-) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 50c79f7554..44e06c42f7 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -309,6 +309,15 @@ menu "Bootloader config" in this area of memory, you can increase it. It must be a multiple of 4 bytes. This area (rtc_retain_mem_t) is reserved and has access from the bootloader and an application. + config BOOTLOADER_FLASH_XMC_SUPPORT + bool "Enable the support for flash chips of XMC (READ HELP FIRST)" + default y + help + Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow. + XMC chips will be forbidden to be used, when this option is disabled. + + DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. + endmenu # Bootloader diff --git a/components/bootloader_support/include/bootloader_flash.h b/components/bootloader_support/include/bootloader_flash.h index 5b74596544..34813dd1ae 100644 --- a/components/bootloader_support/include/bootloader_flash.h +++ b/components/bootloader_support/include/bootloader_flash.h @@ -13,11 +13,24 @@ // limitations under the License. #pragma once +#include #include #include /* including in bootloader for error values */ #include "sdkconfig.h" #include "soc/soc_caps.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Read flash ID by sending 0x9F command + * @return flash raw ID + * mfg_id = (ID >> 16) & 0xFF; + flash_id = ID & 0xffff; + */ +uint32_t bootloader_read_flash_id(void); + #if SOC_CACHE_SUPPORT_WRAP /** * @brief Set the burst mode setting command for specified wrap mode. @@ -28,3 +41,13 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode); #endif +/** + * @brief Startup flow recommended by XMC. Call at startup before any erase/write operation. + * + * @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write). + */ +esp_err_t bootloader_flash_xmc_startup(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/include_bootloader/bootloader_flash_priv.h b/components/bootloader_support/include_bootloader/bootloader_flash_priv.h index 0f23f022c4..8c29aab851 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash_priv.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash_priv.h @@ -37,6 +37,7 @@ #define CMD_RDSR 0x05 #define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ #define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */ +#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */ #define CMD_WRAP 0x77 /* Set burst with wrap command */ @@ -163,11 +164,18 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad */ uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); +/** + * @brief Read the SFDP of the flash + * + * @param sfdp_addr Address of the parameter to read + * @param miso_byte_num Bytes to read + * @return The read SFDP, little endian, 4 bytes at most + */ +uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num); + /** * @brief Enable the flash write protect (WEL bit). */ void bootloader_enable_wp(void); #endif - -#endif diff --git a/components/bootloader_support/include_bootloader/flash_qio_mode.h b/components/bootloader_support/include_bootloader/flash_qio_mode.h index 7f70d5bb08..00592dcf7e 100644 --- a/components/bootloader_support/include_bootloader/flash_qio_mode.h +++ b/components/bootloader_support/include_bootloader/flash_qio_mode.h @@ -13,6 +13,8 @@ // limitations under the License. #pragma once +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index d91c1cb4f3..1699c63d97 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -32,7 +32,9 @@ #endif #if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32/rom/ets_sys.h" #include "esp32s2/rom/spi_flash.h" //For SPI_Encrypt_Write +#include "esp32s2/rom/ets_sys.h" #endif @@ -105,7 +107,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) return spi_flash_erase_range(start_addr, size); } -#else +#else //BOOTLOADER_BUILD /* Bootloader version, uses ROM functions only */ #include "soc/dport_reg.h" #if CONFIG_IDF_TARGET_ESP32 @@ -381,54 +383,99 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) return spi_to_esp_err(rc); } -#endif +#endif // BOOTLOADER_BUILD + +/* dummy_len_plus values defined in ROM for SPI flash configuration */ extern uint8_t g_rom_spiflash_dummy_len_plus[]; -uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) +IRAM_ATTR static 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 = SPIFLASH.ctrl.val; #if CONFIG_IDF_TARGET_ESP32 SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#else SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode #endif - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user.usr_addr = 0; + //command phase SPIFLASH.user.usr_command = 1; SPIFLASH.user2.usr_command_bitlen = 7; - SPIFLASH.user2.usr_command_value = command; - SPIFLASH.user.usr_miso = miso_len > 0; + //addr phase + SPIFLASH.user.usr_addr = addr_len > 0; + SPIFLASH.user1.usr_addr_bitlen = addr_len - 1; #if CONFIG_IDF_TARGET_ESP32 - SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0; + SPIFLASH.addr = (addr_len > 0)? (address << (32-addr_len)) : 0; +#else + SPIFLASH.addr = address; #endif + //dummy phase + if (miso_len > 0) { + uint32_t total_dummy = dummy_len + g_rom_spiflash_dummy_len_plus[1]; + SPIFLASH.user.usr_dummy = total_dummy > 0; + SPIFLASH.user1.usr_dummy_cyclelen = total_dummy - 1; + } else { + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user1.usr_dummy_cyclelen = 0; + } + //output data SPIFLASH.user.usr_mosi = mosi_len > 0; #if CONFIG_IDF_TARGET_ESP32 SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#else SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0; #endif SPIFLASH.data_buf[0] = mosi_data; - - if (g_rom_spiflash_dummy_len_plus[1]) { - /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ - if (miso_len > 0) { - SPIFLASH.user.usr_dummy = 1; - SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1; - } else { - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user1.usr_dummy_cyclelen = 0; - } - } + //input data + SPIFLASH.user.usr_miso = miso_len > 0; +#if CONFIG_IDF_TARGET_ESP32 + SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; +#else + SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0; +#endif SPIFLASH.cmd.usr = 1; while (SPIFLASH.cmd.usr != 0) { } - SPIFLASH.ctrl.val = old_ctrl_reg; - return SPIFLASH.data_buf[0]; + + uint32_t ret = SPIFLASH.data_buf[0]; + if (miso_len < 32) { + //set unused bits to 0 + ret &= ~(UINT32_MAX << miso_len); + } + return ret; +} + +uint32_t 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); +} + +// cmd(0x5A) + 24bit address + 8 cycles dummy +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) @@ -436,6 +483,13 @@ void bootloader_enable_wp(void) bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */ } +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; +} + #if SOC_CACHE_SUPPORT_WRAP esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode) { @@ -466,4 +520,105 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode) SPIFLASH.user.val = reg_bkp_usr; return ESP_OK; } -#endif //SOC_CACHE_SUPPORT_WRAP \ No newline at end of file +#endif //SOC_CACHE_SUPPORT_WRAP + +/******************************************************************************* + * XMC startup flow + ******************************************************************************/ + +#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT +#define XMC_VENDOR_ID 0x20 + +#if BOOTLOADER_BUILD +#define BOOTLOADER_FLASH_LOG(level, ...) ESP_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 +//strictly check the model +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) { + 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) +{ + // If the RDID value is a valid XMC one, may skip the flow + 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 (%08X), skip.", g_rom_flashchip.device_id); + return ESP_OK; + } + + // Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow + 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) { + 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"); + // Enter DPD + bootloader_execute_flash_command(0xB9, 0, 0, 0); + // Enter UDPD + bootloader_execute_flash_command(0x79, 0, 0, 0); + // Exit UDPD + bootloader_execute_flash_command(0xFF, 0, 0, 0); + // Delay tXUDPD + ets_delay_us(2000); + // Release Power-down + bootloader_execute_flash_command(0xAB, 0, 0, 0); + ets_delay_us(20); + // Read flash ID and check again + 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 +//only compare the vendor id +static IRAM_ATTR bool is_xmc_chip(uint32_t rdid) +{ + uint32_t vendor_id = (rdid >> 16) & 0xFF; + return (vendor_id == XMC_VENDOR_ID); +} + +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 //XMC_SUPPORT \ No newline at end of file diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 4b94e5c06a..2073e24cd0 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -455,6 +455,11 @@ esp_err_t bootloader_init(void) bootloader_print_banner(); // update flash ID bootloader_flash_update_id(); + // Check and run XMC startup flow + if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) { + ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!"); + goto err; + } // read bootloader header if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { goto err; diff --git a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c index 7508f4f322..c23ebed7e1 100644 --- a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c +++ b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c @@ -377,6 +377,11 @@ esp_err_t bootloader_init(void) bootloader_print_banner(); // update flash ID bootloader_flash_update_id(); + // Check and run XMC startup flow + if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) { + ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!"); + goto err; + } // read bootloader header if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { goto err; diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index 83d5c5ef5f..2998bc56f2 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -108,14 +108,6 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn, The command passed here is always the on-the-wire command given to the SPI flash unit. */ -/* dummy_len_plus values defined in ROM for SPI flash configuration */ -uint32_t 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_enable_qio_mode(void) { uint32_t raw_flash_id; diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index e097922a33..8a680952fc 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -12,6 +12,8 @@ #include "test_utils.h" #include "ccomp_timer.h" #include "esp_log.h" +#include "bootloader_flash.h" //for bootloader_flash_xmc_startup + struct flash_test_ctx { uint32_t offset; @@ -372,3 +374,22 @@ TEST_CASE("spi_flash deadlock with high priority busy-waiting task", "[spi_flash TEST_ASSERT_EQUAL_INT(uxTaskPriorityGet(NULL), UNITY_FREERTOS_PRIORITY); } #endif // portNUM_PROCESSORS > 1 + + +static IRAM_ATTR NOINLINE_ATTR void test_xmc_startup(void) +{ + extern void spi_flash_disable_interrupts_caches_and_other_cpu(void); + extern void spi_flash_enable_interrupts_caches_and_other_cpu(void); + esp_err_t ret = ESP_OK; + + spi_flash_disable_interrupts_caches_and_other_cpu(); + ret = bootloader_flash_xmc_startup(); + spi_flash_enable_interrupts_caches_and_other_cpu(); + + TEST_ASSERT_EQUAL(ESP_OK, ret); +} + +TEST_CASE("bootloader_flash_xmc_startup can be called when cache disabled", "[spi_flash]") +{ + test_xmc_startup(); +} \ No newline at end of file From e5ac1eb83f3c3b409ffcd805ac7cf31705613639 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 18 Aug 2021 23:55:39 +0800 Subject: [PATCH 6/8] spi_flash: fix the corruption of ROM after calling bootloader_execute_flash_command The user register, especially dummy related ones, needs to be restored, otherwise the ROM function will not work. Introduced in dd40123129bc5670ae081c31d519907f0125e4db. --- components/bootloader_support/src/bootloader_flash.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 1699c63d97..f0f2799db5 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -398,6 +398,8 @@ IRAM_ATTR static uint32_t bootloader_flash_execute_command_common( assert(mosi_len <= 32); assert(miso_len <= 32); uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; + uint32_t old_user_reg = SPIFLASH.user.val; + uint32_t old_user1_reg = SPIFLASH.user1.val; #if CONFIG_IDF_TARGET_ESP32 SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode #else @@ -444,6 +446,8 @@ IRAM_ATTR static uint32_t bootloader_flash_execute_command_common( while (SPIFLASH.cmd.usr != 0) { } SPIFLASH.ctrl.val = old_ctrl_reg; + SPIFLASH.user.val = old_user_reg; + SPIFLASH.user1.val = old_user1_reg; uint32_t ret = SPIFLASH.data_buf[0]; if (miso_len < 32) { From 168880fe7b40a57dc0271d82f2f8532eeef75079 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Fri, 7 May 2021 15:25:06 +0800 Subject: [PATCH 7/8] spi_flash: move the unlock patch to bootloader and add support for GD --- .../include/bootloader_flash.h | 8 ++ .../bootloader_support/src/bootloader_flash.c | 99 ++++++++++++++++++- .../src/esp32/bootloader_esp32.c | 2 +- .../src/esp32s2/bootloader_esp32s2.c | 2 +- components/esp32/cpu_start.c | 3 +- .../esp_rom/include/esp32/rom/spi_flash.h | 2 +- .../esp_rom/include/esp32s2/rom/opi_flash.h | 1 - .../esp_rom/include/esp32s2/rom/spi_flash.h | 1 - .../spi_flash/esp32/spi_flash_rom_patch.c | 2 +- components/spi_flash/flash_ops.c | 6 +- components/spi_flash/sim/flash_mock.cpp | 5 + 11 files changed, 117 insertions(+), 14 deletions(-) diff --git a/components/bootloader_support/include/bootloader_flash.h b/components/bootloader_support/include/bootloader_flash.h index 34813dd1ae..6847916aea 100644 --- a/components/bootloader_support/include/bootloader_flash.h +++ b/components/bootloader_support/include/bootloader_flash.h @@ -48,6 +48,14 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode); */ esp_err_t bootloader_flash_xmc_startup(void); +/** + * @brief Unlock Flash write protect. + * Please do not call this function in SDK. + * + * @note This can be overridden because it's attribute weak. + */ +esp_err_t bootloader_flash_unlock(void); + #ifdef __cplusplus } #endif diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index f0f2799db5..825093944f 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -31,12 +31,25 @@ # define SPIFLASH SPIMEM1 #endif -#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/spi_flash.h" #include "esp32/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/spi_flash.h" //For SPI_Encrypt_Write #include "esp32s2/rom/ets_sys.h" #endif +#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF) +#define ISSI_ID 0x9D +#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_16B BIT9 // QE position when you write 16 bits at one time. +#define ESP_BOOTLOADER_SPIFLASH_QE_8B BIT1 // QE position when you write 8 bits(for SR2) at one time. +#define ESP_BOOTLOADER_SPIFLASH_WRITE_8B (8) +#define ESP_BOOTLOADER_SPIFLASH_WRITE_16B (16) #ifndef BOOTLOADER_BUILD /* Normal app version maps to esp_spi_flash.h operations... @@ -336,7 +349,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool return ESP_FAIL; } - err = spi_to_esp_err(esp_rom_spiflash_unlock()); + err = bootloader_flash_unlock(); if (err != ESP_OK) { return err; } @@ -385,6 +398,86 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) #endif // BOOTLOADER_BUILD +FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip) +{ + return BYTESHIFT(chip->device_id, 2) == ISSI_ID; +} + +// For GD25Q32, GD25Q64, GD25Q127C, GD25Q128, which use single command to read/write different SR. +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; +} + +esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void) +{ + uint16_t status = 0; // status for SR1 or SR1+SR2 if writing SR with 01H + 2Bytes. + uint16_t new_status = 0; + uint8_t status_sr2 = 0; // status_sr2 for SR2. + uint8_t new_status_sr2 = 0; + uint8_t write_sr_bit = 0; + esp_err_t err = ESP_OK; + + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + if (is_issi_chip(&g_rom_flashchip)) { + write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B; + // ISSI chips have different QE position + + status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8); + + /* Clear all bits in the mask. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + new_status = status & (~ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI); + // Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing. + } else if (is_gd_q_chip(&g_rom_flashchip)) { + /* The GD chips behaviour is to clear all bits in SR1 and clear bits in SR2 except QE bit. + Use 01H to write SR1 and 31H to write SR2. + */ + write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B; + + status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8); + new_status = 0; + + status_sr2 = bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8); + new_status_sr2 = status_sr2 & ESP_BOOTLOADER_SPIFLASH_QE_8B; + } else { + /* For common behaviour, like XMC chips, Use 01H+2Bytes to write both SR1 and SR2*/ + write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_16B; + status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8); + + /* Clear all bits except QE, if it is set. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + new_status = status & ESP_BOOTLOADER_SPIFLASH_QE_16B; + } + + if (status != new_status) { + /* if the status in SR not equal to the ideal status, the status need to be updated */ + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WREN, 0, 0, 0); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WRSR, new_status, write_sr_bit, 0); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + } + + if (status_sr2 != new_status_sr2) { + /* If the status in SR2 not equal to the ideal status, the status need to be updated. + It doesn't need to be updated if status in SR2 is 0. + Note: if we need to update both SR1 and SR2, the `CMD_WREN` needs to be sent again. + */ + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WREN, 0, 0, 0); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WRSR2, new_status_sr2, write_sr_bit, 0); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + } + + bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + return err; +} + /* dummy_len_plus values defined in ROM for SPI flash configuration */ extern uint8_t g_rom_spiflash_dummy_len_plus[]; @@ -457,7 +550,7 @@ IRAM_ATTR static uint32_t bootloader_flash_execute_command_common( return ret; } -uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) +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; diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 2073e24cd0..5a1c9251c4 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -260,7 +260,7 @@ static esp_err_t bootloader_init_spi_flash(void) } #endif - esp_rom_spiflash_unlock(); + bootloader_flash_unlock(); #if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT bootloader_enable_qio_mode(); diff --git a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c index c23ebed7e1..123733c645 100644 --- a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c +++ b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c @@ -206,7 +206,7 @@ static esp_err_t bootloader_init_spi_flash(void) } #endif - esp_rom_spiflash_unlock(); + bootloader_flash_unlock(); #if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT bootloader_enable_qio_mode(); diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index cec85d8dd9..c0877feb67 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -70,6 +70,7 @@ #include "esp_ota_ops.h" #include "esp_efuse.h" #include "bootloader_flash_config.h" +#include "bootloader_flash.h" #include "bootloader_mem.h" #ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM @@ -439,7 +440,7 @@ void start_cpu0_default(void) extern void esp_rom_spiflash_attach(uint32_t, bool); esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false); - esp_rom_spiflash_unlock(); + bootloader_flash_unlock(); #else // This assumes that DROM is the first segment in the application binary, i.e. that we can read // the binary header through cache by accessing SOC_DROM_LOW address. diff --git a/components/esp_rom/include/esp32/rom/spi_flash.h b/components/esp_rom/include/esp32/rom/spi_flash.h index 6174f05e73..9892243d39 100644 --- a/components/esp_rom/include/esp32/rom/spi_flash.h +++ b/components/esp_rom/include/esp32/rom/spi_flash.h @@ -260,7 +260,7 @@ esp_rom_spiflash_result_t esp_rom_spiflash_read_status(esp_rom_spiflash_chip_t * esp_rom_spiflash_result_t esp_rom_spiflash_read_statushigh(esp_rom_spiflash_chip_t *spi, uint32_t *status); /** - * @brief Write status to Falsh status register. + * @brief Write status to Flash status register. * Please do not call this function in SDK. * * @param esp_rom_spiflash_chip_t *spi : The information for Flash, which is exported from ld file. diff --git a/components/esp_rom/include/esp32s2/rom/opi_flash.h b/components/esp_rom/include/esp32s2/rom/opi_flash.h index c985810b67..bb209f67f0 100644 --- a/components/esp_rom/include/esp32s2/rom/opi_flash.h +++ b/components/esp_rom/include/esp32s2/rom/opi_flash.h @@ -40,7 +40,6 @@ typedef struct { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 -#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2) #define FLASH_OP_MODE_RDCMD_DOUT 0x3B #define ESP_ROM_FLASH_SECTOR_SIZE 0x1000 diff --git a/components/esp_rom/include/esp32s2/rom/spi_flash.h b/components/esp_rom/include/esp32s2/rom/spi_flash.h index 2cf631666c..1eee20a5fa 100644 --- a/components/esp_rom/include/esp32s2/rom/spi_flash.h +++ b/components/esp_rom/include/esp32s2/rom/spi_flash.h @@ -119,7 +119,6 @@ extern "C" { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 -#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2) #define FLASH_ID_GD25LQ32C 0xC86016 diff --git a/components/spi_flash/esp32/spi_flash_rom_patch.c b/components/spi_flash/esp32/spi_flash_rom_patch.c index 6aa469686a..fde48e952c 100644 --- a/components/spi_flash/esp32/spi_flash_rom_patch.c +++ b/components/spi_flash/esp32/spi_flash_rom_patch.c @@ -64,7 +64,7 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp about interrupts, CPU coordination, flash mapping. However some of the functions in esp_spi_flash.c call it. */ -esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void) +__attribute__((__unused__)) esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void) { uint32_t status; uint32_t new_status; diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 7372d1c124..28d91d57e9 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -42,6 +42,7 @@ #include "esp_flash.h" #include "esp_attr.h" #include "esp_timer.h" +#include "bootloader_flash.h" esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size); @@ -199,11 +200,8 @@ static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(void) static bool unlocked = false; if (!unlocked) { spi_flash_guard_start(); - esp_rom_spiflash_result_t rc = esp_rom_spiflash_unlock(); + bootloader_flash_unlock(); spi_flash_guard_end(); - if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { - return rc; - } unlocked = true; } return ESP_ROM_SPIFLASH_RESULT_OK; diff --git a/components/spi_flash/sim/flash_mock.cpp b/components/spi_flash/sim/flash_mock.cpp index b089e22dc8..7386734262 100644 --- a/components/spi_flash/sim/flash_mock.cpp +++ b/components/spi_flash/sim/flash_mock.cpp @@ -75,6 +75,11 @@ extern "C" int spi_flash_get_erase_cycles(size_t sector) return spiflash.get_erase_cycles(sector); } +extern "C" esp_err_t bootloader_flash_unlock(void) +{ + return ESP_OK; +} + esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t target, uint32_t *dest, int32_t len) { return spiflash.read(target, dest, len); From ac6f45d29040842364284ada3f149fff1bd1797e Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 17 Sep 2021 15:38:37 +0800 Subject: [PATCH 8/8] bootloader: support unlock MXIC flash chips --- .../bootloader_support/src/bootloader_flash.c | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 825093944f..8f860486a0 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -41,15 +41,15 @@ #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_16B BIT9 // QE position when you write 16 bits at one time. -#define ESP_BOOTLOADER_SPIFLASH_QE_8B BIT1 // QE position when you write 8 bits(for SR2) at one time. -#define ESP_BOOTLOADER_SPIFLASH_WRITE_8B (8) -#define ESP_BOOTLOADER_SPIFLASH_WRITE_16B (16) +#define ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2 BIT1 // QE position when you write 8 bits(for SR2) at one time. +#define ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE BIT9 // QE position when you write 16 bits at one time. + #ifndef BOOTLOADER_BUILD /* Normal app version maps to esp_spi_flash.h operations... @@ -409,72 +409,77 @@ 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) { + // At the beginning status == new_status == status_sr2 == new_status_sr2 == 0. + // If the register doesn't need to be updated, keep them the same (0), so that no command will be actually sent. uint16_t status = 0; // status for SR1 or SR1+SR2 if writing SR with 01H + 2Bytes. uint16_t new_status = 0; uint8_t status_sr2 = 0; // status_sr2 for SR2. uint8_t new_status_sr2 = 0; - uint8_t write_sr_bit = 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)) { - write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B; - // ISSI chips have different QE position - + if (is_issi_chip(&g_rom_flashchip) || is_mxic_chip(&g_rom_flashchip)) { + // Currently ISSI & MXIC share the same command and register layout, which is different from the default model. + // If any code here needs to be modified, check both chips. status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8); /* Clear all bits in the mask. (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) */ + sr1_bit_num = 8; new_status = status & (~ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI); - // Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing. } else if (is_gd_q_chip(&g_rom_flashchip)) { /* The GD chips behaviour is to clear all bits in SR1 and clear bits in SR2 except QE bit. Use 01H to write SR1 and 31H to write SR2. */ - write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B; - 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_8B; + new_status_sr2 = status_sr2 & ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2; } else { /* For common behaviour, like XMC chips, Use 01H+2Bytes to write both SR1 and SR2*/ - write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_16B; status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8); /* Clear all bits except QE, if it is set. (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) */ - new_status = status & ESP_BOOTLOADER_SPIFLASH_QE_16B; + sr1_bit_num = 16; + new_status = status & ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE; } + // When SR is written, set to true to indicate that WRDI need to be sent to ensure the protection is ON before return. + bool status_written = false; + // Skip if nothing needs to be changed. Meaningless writing to SR increases the risk during write and wastes time. if (status != new_status) { - /* if the status in SR not equal to the ideal status, the status need to be updated */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); bootloader_execute_flash_command(CMD_WREN, 0, 0, 0); - esp_rom_spiflash_wait_idle(&g_rom_flashchip); - bootloader_execute_flash_command(CMD_WRSR, new_status, write_sr_bit, 0); - esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WRSR, new_status, sr1_bit_num, 0); + status_written = true; } if (status_sr2 != new_status_sr2) { - /* If the status in SR2 not equal to the ideal status, the status need to be updated. - It doesn't need to be updated if status in SR2 is 0. - Note: if we need to update both SR1 and SR2, the `CMD_WREN` needs to be sent again. - */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); bootloader_execute_flash_command(CMD_WREN, 0, 0, 0); - esp_rom_spiflash_wait_idle(&g_rom_flashchip); - bootloader_execute_flash_command(CMD_WRSR2, new_status_sr2, write_sr_bit, 0); - esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WRSR2, new_status_sr2, 8, 0); + status_written = true; + } + + if (status_written) { + //Call esp_rom_spiflash_wait_idle to make sure previous WRSR is completed. + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); } - bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); - esp_rom_spiflash_wait_idle(&g_rom_flashchip); return err; }