diff --git a/components/app_update/test/test_switch_ota.c b/components/app_update/test/test_switch_ota.c index af87f6e7fb..5523a2e3eb 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/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index d3f1129285..aa58fc53d2 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -308,6 +308,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 new file mode 100644 index 0000000000..6847916aea --- /dev/null +++ b/components/bootloader_support/include/bootloader_flash.h @@ -0,0 +1,61 @@ +// 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 +#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. + * + * @param mode The specified warp mode. + * @return always ESP_OK + */ +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); + +/** + * @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/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash_priv.h similarity index 75% rename from components/bootloader_support/include_bootloader/bootloader_flash.h rename to components/bootloader_support/include_bootloader/bootloader_flash_priv.h index 6482dde99e..8c29aab851 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash_priv.h @@ -19,11 +19,28 @@ #include #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 #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_RDSFDP 0x5A /* Read the SFDP of the flash */ +#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 +153,29 @@ 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 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 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_common.c b/components/bootloader_support/src/bootloader_common.c index 5b6baeb56f..767805f0e6 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -28,7 +28,7 @@ #include "esp32s2beta/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 358aa134be..60ef146bf3 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -13,13 +13,44 @@ // limitations under the License. #include -#include +#include #include #include -#if CONFIG_IDF_TARGET_ESP32S2BETA -#include "esp32s2beta/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_ESP32 +#include "esp32/rom/spi_flash.h" +#include "esp32/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2BETA +#include "esp32s2beta/rom/spi_flash.h" +#include "esp32s2beta/rom/ets_sys.h" +#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 // 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... */ @@ -89,7 +120,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 #if CONFIG_IDF_TARGET_ESP32 @@ -317,7 +348,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; } @@ -363,4 +394,332 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) } return spi_to_esp_err(rc); } + +#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; +} + +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 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)) { + // 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); + } 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. + */ + 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 { + /* For common behaviour, like XMC chips, Use 01H+2Bytes to write both SR1 and SR2*/ + 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.) + */ + 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) { + 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) { + //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); + } + + return err; +} + + +/* dummy_len_plus values defined in ROM for SPI flash configuration */ +extern uint8_t g_rom_spiflash_dummy_len_plus[]; +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; + 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 + SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode #endif + //command phase + SPIFLASH.user.usr_command = 1; + SPIFLASH.user2.usr_command_bitlen = 7; + SPIFLASH.user2.usr_command_value = command; + //addr phase + SPIFLASH.user.usr_addr = addr_len > 0; + SPIFLASH.user1.usr_addr_bitlen = addr_len - 1; +#if CONFIG_IDF_TARGET_ESP32 + 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; +#else + SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0; +#endif + SPIFLASH.data_buf[0] = mosi_data; + //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; + SPIFLASH.user.val = old_user_reg; + SPIFLASH.user1.val = old_user1_reg; + + 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 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); +} + +// 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) +{ + 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) +{ + 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 + +/******************************************************************************* + * 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_EARLY_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/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 2a1f1e4849..1ebf43e26a 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 8343041774..87fb406045 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -57,7 +57,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 d488a62f0d..ffb61b9a4b 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -22,6 +22,7 @@ #include "bootloader_clock.h" #include "bootloader_common.h" #include "bootloader_flash_config.h" +#include "bootloader_flash_priv.h" #include "soc/cpu.h" #include "soc/dport_reg.h" @@ -257,7 +258,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(); @@ -265,6 +266,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; } @@ -450,6 +453,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/esp32/flash_encrypt.c b/components/bootloader_support/src/esp32/flash_encrypt.c index 8e07095cee..5cecbc78ab 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 a8110b3a2e..49c95f15bd 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/esp32s2beta/bootloader_esp32s2beta.c b/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c index 066271e4f7..5aa759f655 100644 --- a/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c +++ b/components/bootloader_support/src/esp32s2beta/bootloader_esp32s2beta.c @@ -24,6 +24,7 @@ #include "bootloader_init.h" #include "bootloader_clock.h" #include "bootloader_flash_config.h" +#include "bootloader_flash_priv.h" #include "esp32s2beta/rom/cache.h" #include "esp32s2beta/rom/ets_sys.h" @@ -217,7 +218,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(); @@ -225,6 +226,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; } @@ -376,6 +379,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/esp32s2beta/flash_encrypt.c b/components/bootloader_support/src/esp32s2beta/flash_encrypt.c index bef51c827e..6d5bfb1060 100644 --- a/components/bootloader_support/src/esp32s2beta/flash_encrypt.c +++ b/components/bootloader_support/src/esp32s2beta/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" diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 1b753fbd17..81dc0821e1 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 1dac9c5fc6..fbfd683e24 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_priv.h" #include "esp_log.h" #include "esp_err.h" #if CONFIG_IDF_TARGET_ESP32 @@ -25,30 +26,10 @@ #include "esp32s2beta/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_ESP32S2BETA -#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,56 +107,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. */ -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); - id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); - return id; -} - -#if CONFIG_IDF_TARGET_ESP32S2BETA -#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) { @@ -208,8 +139,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_ESP32S2BETA - spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); +#if SOC_CACHE_SUPPORT_WRAP + bootloader_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); #endif } @@ -226,7 +157,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 +195,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_ESP32S2BETA - 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_ESP32S2BETA - 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_ESP32S2BETA - 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/bootloader_support/src/idf/bootloader_sha.c b/components/bootloader_support/src/idf/bootloader_sha.c index 06fdc358d2..a0a5cbcc99 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 ca66be7059..15920a6e35 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" @@ -273,7 +273,7 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa break; } } - + free(sig_be); free(buf); return (!ret) ? ESP_OK : ESP_ERR_IMAGE_INVALID; diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index 08b4f36e5c..11966d8183 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; diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 84ba66c742..f09b2d3913 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" #ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM #include "esp32/rom/efuse.h" @@ -430,7 +431,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 f4b17ae5be..9892243d39 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 @@ -259,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/soc/esp32s2beta/include/soc/soc_caps.h b/components/soc/esp32s2beta/include/soc/soc_caps.h index 85a465e89f..1db501548c 100644 --- a/components/soc/esp32s2beta/include/soc/soc_caps.h +++ b/components/soc/esp32s2beta/include/soc/soc_caps.h @@ -4,3 +4,5 @@ // include them here. #pragma once + +#define SOC_CACHE_SUPPORT_WRAP 1 diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index b077d6c6de..46574c4c5a 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 @@ -12,6 +10,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 f40b0b8340..e0c679ed3b 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 125c2dfa56..34e8e3837b 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; @@ -58,28 +64,46 @@ 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; 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/esp32s2beta/flash_ops_esp32s2beta.c b/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c index 876fb0e62b..d46716ec57 100644 --- a/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c +++ b/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c @@ -20,6 +20,7 @@ #include "soc/soc_memory_layout.h" #include "esp32s2beta/rom/spi_flash.h" #include "esp32s2beta/rom/cache.h" +#include "bootloader_flash.h" #include "hal/spi_flash_hal.h" #include "esp_flash.h" @@ -71,48 +72,22 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a #define SPICACHE SPIMEM0 #define SPIFLASH SPIMEM1 -#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; } @@ -120,7 +95,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/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index e5d922e585..26c0cc1570 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -503,7 +503,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; @@ -544,28 +564,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; @@ -577,7 +586,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.1, 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; @@ -596,31 +626,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; } diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index f9f532045c..4d449c54a7 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -35,14 +35,13 @@ #include "esp32/clk.h" #elif CONFIG_IDF_TARGET_ESP32S2BETA #include "esp32s2beta/clk.h" -#include "soc/spi_mem_reg.h" -#include "soc/spi_mem_struct.h" #endif #include "esp_flash_partitions.h" #include "cache_utils.h" #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); @@ -200,11 +199,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; @@ -832,6 +828,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_ESP32S2BETA) // TODO esp32s2beta: Remove once ESP32S2Beta has new SPI Flash API support esp_flash_t *esp_flash_default_chip = NULL; 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); diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index 475fd510bb..a2c4ae2746 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 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");