mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 04:59:55 +00:00 
			
		
		
		
	bootloader: add xmc spi_flash startup flow to improve reliability
This commit is contained in:
		| @@ -365,6 +365,15 @@ menu "Bootloader config" | |||||||
|             in this area of memory, you can increase it. It must be a multiple of 4 bytes. |             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. |             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 | endmenu  # Bootloader | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,10 +18,19 @@ | |||||||
| #include "sdkconfig.h" | #include "sdkconfig.h" | ||||||
| #include "soc/soc_caps.h" | #include "soc/soc_caps.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief Read flash ID by sending RDID command (0x9F) | ||||||
|  |  * @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 | #if SOC_CACHE_SUPPORT_WRAP | ||||||
| /** | /** | ||||||
|  * @brief Set the burst mode setting command for specified wrap mode. |  * @brief Set the burst mode setting command for specified wrap mode. | ||||||
| @@ -40,6 +49,13 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode); | |||||||
|   */ |   */ | ||||||
| esp_err_t bootloader_flash_unlock(void); | esp_err_t bootloader_flash_unlock(void); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief Startup flow recommended by XMC. Call at startup before any erase/write operation. | ||||||
|  |  * | ||||||
|  |  * @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write). | ||||||
|  |  */ | ||||||
|  | esp_err_t bootloader_flash_xmc_startup(void); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ | |||||||
| #define CMD_RDSR       0x05 | #define CMD_RDSR       0x05 | ||||||
| #define CMD_RDSR2      0x35 /* Not all SPI flash uses this command */ | #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_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 */ | #define CMD_WRAP       0x77 /* Set burst with wrap command */ | ||||||
| #define CMD_RESUME     0x7A /* Resume command to clear flash suspend bit */ | #define CMD_RESUME     0x7A /* Resume command to clear flash suspend bit */ | ||||||
|  |  | ||||||
| @@ -164,6 +165,15 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad | |||||||
|  */ |  */ | ||||||
| uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); | 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). |  * @brief Enable the flash write protect (WEL bit). | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -122,7 +122,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) | |||||||
|     return spi_flash_erase_range(start_addr, size); |     return spi_flash_erase_range(start_addr, size); | ||||||
| } | } | ||||||
|  |  | ||||||
| #else | #else //BOOTLOADER_BUILD | ||||||
| /* Bootloader version, uses ROM functions only */ | /* Bootloader version, uses ROM functions only */ | ||||||
| #if CONFIG_IDF_TARGET_ESP32 | #if CONFIG_IDF_TARGET_ESP32 | ||||||
| #include "esp32/rom/spi_flash.h" | #include "esp32/rom/spi_flash.h" | ||||||
| @@ -453,7 +453,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) | |||||||
|     return spi_to_esp_err(rc); |     return spi_to_esp_err(rc); | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif | #endif // BOOTLOADER_BUILD | ||||||
|  |  | ||||||
| FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip) | FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip) | ||||||
| { | { | ||||||
| @@ -535,29 +535,47 @@ esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void) | |||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* dummy_len_plus values defined in ROM for SPI flash configuration */ | ||||||
| #ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here | #ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here | ||||||
| extern uint8_t g_rom_spiflash_dummy_len_plus[]; | extern uint8_t g_rom_spiflash_dummy_len_plus[]; | ||||||
| #endif | #endif | ||||||
| uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) | IRAM_ATTR static uint32_t bootloader_flash_execute_command_common( | ||||||
|  |     uint8_t command, | ||||||
|  |     uint32_t addr_len, uint32_t address, | ||||||
|  |     uint8_t dummy_len, | ||||||
|  |     uint8_t mosi_len, uint32_t mosi_data, | ||||||
|  |     uint8_t miso_len) | ||||||
| { | { | ||||||
|  |     assert(mosi_len <= 32); | ||||||
|  |     assert(miso_len <= 32); | ||||||
|     uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; |     uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; | ||||||
| #if CONFIG_IDF_TARGET_ESP32 | #if CONFIG_IDF_TARGET_ESP32 | ||||||
|     SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode |     SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode | ||||||
| #else | #else | ||||||
|     SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode |     SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode | ||||||
| #endif | #endif | ||||||
|     SPIFLASH.user.usr_dummy = 0; |     //command phase | ||||||
|     SPIFLASH.user.usr_addr = 0; |  | ||||||
|     SPIFLASH.user.usr_command = 1; |     SPIFLASH.user.usr_command = 1; | ||||||
|     SPIFLASH.user2.usr_command_bitlen = 7; |     SPIFLASH.user2.usr_command_bitlen = 7; | ||||||
|  |  | ||||||
|     SPIFLASH.user2.usr_command_value = command; |     SPIFLASH.user2.usr_command_value = command; | ||||||
|     SPIFLASH.user.usr_miso = miso_len > 0; |     //addr phase | ||||||
|  |     SPIFLASH.user.usr_addr = addr_len > 0; | ||||||
|  |     SPIFLASH.user1.usr_addr_bitlen = addr_len - 1; | ||||||
| #if CONFIG_IDF_TARGET_ESP32 | #if CONFIG_IDF_TARGET_ESP32 | ||||||
|     SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; |     SPIFLASH.addr = (addr_len > 0)? (address << (32-addr_len)) : 0; | ||||||
| #else | #else | ||||||
|     SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0; |     SPIFLASH.addr = address; | ||||||
| #endif | #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; |     SPIFLASH.user.usr_mosi = mosi_len > 0; | ||||||
| #if CONFIG_IDF_TARGET_ESP32 | #if CONFIG_IDF_TARGET_ESP32 | ||||||
|     SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; |     SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; | ||||||
| @@ -565,24 +583,50 @@ uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mo | |||||||
|     SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0; |     SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0; | ||||||
| #endif | #endif | ||||||
|     SPIFLASH.data_buf[0] = mosi_data; |     SPIFLASH.data_buf[0] = mosi_data; | ||||||
|  |     //input data | ||||||
|     if (g_rom_spiflash_dummy_len_plus[1]) { |     SPIFLASH.user.usr_miso = miso_len > 0; | ||||||
|         /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ | #if CONFIG_IDF_TARGET_ESP32 | ||||||
|         if (miso_len > 0) { |     SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0; | ||||||
|             SPIFLASH.user.usr_dummy = 1; | #else | ||||||
|             SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1; |     SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0; | ||||||
|         } else { | #endif | ||||||
|             SPIFLASH.user.usr_dummy = 0; |  | ||||||
|             SPIFLASH.user1.usr_dummy_cyclelen = 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     SPIFLASH.cmd.usr = 1; |     SPIFLASH.cmd.usr = 1; | ||||||
|     while (SPIFLASH.cmd.usr != 0) { |     while (SPIFLASH.cmd.usr != 0) { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     SPIFLASH.ctrl.val = old_ctrl_reg; |     SPIFLASH.ctrl.val = old_ctrl_reg; | ||||||
|     return SPIFLASH.data_buf[0]; |  | ||||||
|  |     uint32_t ret = SPIFLASH.data_buf[0]; | ||||||
|  |     if (miso_len < 32) { | ||||||
|  |         //set unused bits to 0 | ||||||
|  |         ret &= ~(UINT32_MAX << miso_len); | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t 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) | void bootloader_enable_wp(void) | ||||||
| @@ -590,6 +634,13 @@ void bootloader_enable_wp(void) | |||||||
|     bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);   /* Exit OTP mode */ |     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 | #if SOC_CACHE_SUPPORT_WRAP | ||||||
| esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode) | esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode) | ||||||
| { | { | ||||||
| @@ -621,3 +672,104 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode) | |||||||
|     return ESP_OK; |     return ESP_OK; | ||||||
| } | } | ||||||
| #endif //SOC_CACHE_SUPPORT_WRAP | #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 | ||||||
|  |     esp_rom_delay_us(2000); | ||||||
|  |     // Release Power-down | ||||||
|  |     bootloader_execute_flash_command(0xAB, 0, 0, 0); | ||||||
|  |     esp_rom_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 | ||||||
|   | |||||||
| @@ -388,6 +388,11 @@ esp_err_t bootloader_init(void) | |||||||
|     bootloader_print_banner(); |     bootloader_print_banner(); | ||||||
|     // update flash ID |     // update flash ID | ||||||
|     bootloader_flash_update_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 |     // read bootloader header | ||||||
|     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { |     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { | ||||||
|         goto err; |         goto err; | ||||||
|   | |||||||
| @@ -329,6 +329,11 @@ esp_err_t bootloader_init(void) | |||||||
|     bootloader_print_banner(); |     bootloader_print_banner(); | ||||||
|     // update flash ID |     // update flash ID | ||||||
|     bootloader_flash_update_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 |     // read bootloader header | ||||||
|     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { |     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { | ||||||
|         goto err; |         goto err; | ||||||
|   | |||||||
| @@ -310,6 +310,11 @@ esp_err_t bootloader_init(void) | |||||||
|     bootloader_print_banner(); |     bootloader_print_banner(); | ||||||
|     // update flash ID |     // update flash ID | ||||||
|     bootloader_flash_update_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 |     // read bootloader header | ||||||
|     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { |     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { | ||||||
|         goto err; |         goto err; | ||||||
|   | |||||||
| @@ -318,6 +318,11 @@ esp_err_t bootloader_init(void) | |||||||
|     bootloader_print_banner(); |     bootloader_print_banner(); | ||||||
|     // update flash ID |     // update flash ID | ||||||
|     bootloader_flash_update_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 |     // read bootloader header | ||||||
|     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { |     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { | ||||||
|         goto err; |         goto err; | ||||||
|   | |||||||
| @@ -111,14 +111,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. |    The command passed here is always the on-the-wire command given to the SPI flash unit. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| /* dummy_len_plus values defined in ROM for SPI flash configuration */ |  | ||||||
| uint32_t bootloader_read_flash_id(void) |  | ||||||
| { |  | ||||||
|     uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24); |  | ||||||
|     id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); |  | ||||||
|     return id; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void bootloader_enable_qio_mode(void) | void bootloader_enable_qio_mode(void) | ||||||
| { | { | ||||||
|     uint32_t raw_flash_id; |     uint32_t raw_flash_id; | ||||||
|   | |||||||
| @@ -15,6 +15,8 @@ | |||||||
| #include "esp_rom_sys.h" | #include "esp_rom_sys.h" | ||||||
| #include "esp_timer.h" | #include "esp_timer.h" | ||||||
|  |  | ||||||
|  | #include "bootloader_flash.h"   //for bootloader_flash_xmc_startup | ||||||
|  |  | ||||||
| #include "sdkconfig.h" | #include "sdkconfig.h" | ||||||
| #if CONFIG_IDF_TARGET_ESP32 | #if CONFIG_IDF_TARGET_ESP32 | ||||||
| #include "esp32/rom/spi_flash.h" | #include "esp32/rom/spi_flash.h" | ||||||
| @@ -419,3 +421,21 @@ TEST_CASE("rom unlock will not erase QE bit", "[spi_flash]") | |||||||
|     TEST_ASSERT(status & 0x40); |     TEST_ASSERT(status & 0x40); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 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(); | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Michael (XIAO Xufeng)
					Michael (XIAO Xufeng)