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/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 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 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 9aadb8fc14..8f860486a0 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_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_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 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 "soc/dport_reg.h" #if CONFIG_IDF_TARGET_ESP32 @@ -318,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; } @@ -364,4 +395,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_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/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 19d712dd3f..5a1c9251c4 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_priv.h" #include "soc/cpu.h" #include "soc/dport_reg.h" @@ -259,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(); @@ -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; } @@ -452,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/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 050d0afda5..123733c645 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_priv.h" #include "esp32s2/rom/cache.h" #include "esp32s2/rom/ets_sys.h" @@ -205,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(); @@ -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; } @@ -374,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/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 e08824b932..2998bc56f2 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 "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,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_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) { @@ -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_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 +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_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/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; 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 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/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..fde48e952c 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/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/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; } diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index f6fc2443bf..28d91d57e9 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -36,14 +36,13 @@ #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" #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); @@ -201,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; @@ -833,6 +829,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; 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 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 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");