chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:04:25 +08:00
commit 548b49ebc0
20937 changed files with 5455372 additions and 0 deletions
@@ -0,0 +1,73 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <esp_err.h>
#include "spi_flash_mmap.h" /* including in bootloader for error values */
#include "esp_private/spi_flash_os.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "bootloader_flash_override.h"
#ifdef __cplusplus
extern "C" {
#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);
/**
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
*
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indicating 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, when there is a same name symbol.
*/
esp_err_t bootloader_flash_unlock(void);
/**
* @brief Unlock Flash write protect.
* This is alias to `bootloader_flash_unlock`.
* Please do not call this function in SDK.
*/
esp_err_t bootloader_flash_unlock_default(void);
/**
* @brief Reset the flash chip (66H + 99H).
*
* @return ESP_OK if success, otherwise ESP_FAIL.
*/
esp_err_t bootloader_flash_reset_chip(void);
/**
* @brief Check if octal flash mode is enabled in eFuse
*
* @return True if flash is in octal mode, false else
*/
bool bootloader_flash_is_octal_mode_enabled(void);
/**
* @brief Get the spi flash working mode.
*
* @return The mode of flash working mode, see `esp_rom_spiflash_read_mode_t`
*/
esp_rom_spiflash_read_mode_t bootloader_flash_get_spi_mode(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,93 @@
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "esp_image_format.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Update the flash id in g_rom_flashchip(global esp_rom_spiflash_chip_t structure).
*
* @return None
*/
void bootloader_flash_update_id(void);
/**
* @brief Update the flash size in g_rom_flashchip (global esp_rom_spiflash_chip_t structure).
*
* @param size The size to store, in bytes.
* @return None
*/
void bootloader_flash_update_size(uint32_t size);
/**
* @brief Set the flash CS setup and hold time.
*
* @note CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T.
* cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1.
*
* @return None
*/
void bootloader_flash_cs_timing_config(void);
/**
* @brief Configure SPI flash clock.
*
* @note This function only set clock frequency for SPI0.
*
* @param pfhdr Pointer to App image header, from where to fetch flash settings.
*
* @return None
*/
void bootloader_flash_clock_config(const esp_image_header_t* pfhdr);
/**
* @brief Configure SPI flash gpio, include the IO matrix and drive strength configuration.
*
* @param pfhdr Pointer to App image header, from where to fetch flash settings.
*
* @return None
*/
void bootloader_flash_gpio_config(const esp_image_header_t* pfhdr);
#ifdef CONFIG_IDF_TARGET_ESP32
/**
* @brief Configure SPI flash read dummy based on different mode and frequency.
*
* @param pfhdr Pointer to App image header, from where to fetch flash settings.
*
* @return None
*/
void bootloader_flash_dummy_config(const esp_image_header_t* pfhdr);
#else
// The meaning has changed on this chip. Deprecated, Call `bootloader_configure_spi_pins()` and `bootloader_flash_set_dummy_out()` directly.
void bootloader_flash_dummy_config(const esp_image_header_t* pfhdr) __attribute__((deprecated));
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
/**
* @brief Return the pin number used for custom SPI flash and/or SPIRAM WP pin
*
* Can be determined by eFuse values in most cases, or overriden in configuration
*
* This value is only meaningful if the other SPI flash pins are overriden via eFuse.
*
* This value is only meaningful if flash is set to QIO or QOUT mode, or if
* SPIRAM is enabled.
*
* @return Pin number to use, or -1 if the default should be kept
*/
int bootloader_flash_get_wp_pin(void);
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,130 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned (*bootloader_flash_read_status_fn_t)(void);
typedef void (*bootloader_flash_write_status_fn_t)(unsigned);
typedef struct __attribute__((packed))
{
const char *manufacturer;
uint8_t mfg_id; /* 8-bit JEDEC manufacturer ID */
uint16_t flash_id; /* 16-bit JEDEC flash chip ID */
uint16_t id_mask; /* Bits to match on in flash chip ID */
bootloader_flash_read_status_fn_t read_status_fn;
bootloader_flash_write_status_fn_t write_status_fn;
uint8_t status_qio_bit;
} bootloader_qio_info_t;
/**
* @brief Read 8 bit status using RDSR command
*
* @return Value of SR1.
*/
unsigned bootloader_read_status_8b_rdsr(void);
/**
* @brief Read 8 bit status (second byte) using RDSR2 command
*
* @return Value of SR2
*/
unsigned bootloader_read_status_8b_rdsr2(void);
/**
* @brief Read 8 bit status (third byte) using RDSR3 command
*
* @return Value of SR3
*/
unsigned bootloader_read_status_8b_rdsr3(void);
/**
* @brief Read 16 bit status using RDSR & RDSR2 (low and high bytes)
*
* @return Value of SR2#SR1.
*/
unsigned bootloader_read_status_16b_rdsr_rdsr2(void);
/**
* @brief Write 8 bit status using WRSR
*/
void bootloader_write_status_8b_wrsr(unsigned new_status);
/**
* @brief Write 8 bit status (second byte) using WRSR2.
*/
void bootloader_write_status_8b_wrsr2(unsigned new_status);
/**
* @brief Write 8 bit status (third byte) using WRSR3.
*/
void bootloader_write_status_8b_wrsr3(unsigned new_status);
/**
* @brief Write 16 bit status using WRSR, (both write SR1 and SR2)
*/
void bootloader_write_status_16b_wrsr(unsigned new_status);
/**
* @brief Read 8 bit status of XM25QU64A.
*
* @return Value of 8 bit SR.
*/
unsigned bootloader_read_status_8b_xmc25qu64a(void);
/**
* @brief Write 8 bit status for XM25QU64A
*/
void bootloader_write_status_8b_xmc25qu64a(unsigned new_status);
/* Array of known flash chips and data to enable Quad I/O mode
Manufacturer & flash ID can be tested by running "esptool
flash-id"
If manufacturer ID matches, and flash ID ORed with flash ID mask
matches, enable_qio_mode() will execute "Read Cmd", test if bit
number "QIE Bit" is set, and if not set it will call "Write Cmd"
with this bit set.
Searching of this table stops when the first match is found.
*/
extern const bootloader_qio_info_t* bootloader_flash_qe_support_list;
/**
* @brief The bootloader flash qe list count number.
*/
extern uint8_t bootloader_flash_qe_list_count;
/**
* @brief Unlock Flash write protect.
* Please do not call this function in SDK.
*
* @note This can be overridden because it's attribute weak, when there is a same name symbol.
*/
esp_err_t bootloader_flash_unlock(void);
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH || CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_OCTAL_FLASH
/**
* @brief Enable 32bits address flash(larger than 16MB) can map to cache.
*
* @param flash_mode SPI flash working mode.
*
* @note This can be overridden because it's attribute weak, when there is a same name symbol.
*/
void __attribute__((weak)) bootloader_flash_32bits_address_map_enable(esp_rom_spiflash_read_mode_t flash_mode);
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,207 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BOOTLOADER_FLASH_H
#define __BOOTLOADER_FLASH_H
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <esp_err.h>
#include <spi_flash_mmap.h> /* including in bootloader for error values */
#include "sdkconfig.h"
#include "bootloader_flash.h"
#include "soc/ext_mem_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_BLOCK_SIZE 0x10000
#define MMAP_ALIGNED_MASK (SPI_FLASH_MMU_PAGE_SIZE - 1)
#define MMU_FLASH_MASK (~(SPI_FLASH_MMU_PAGE_SIZE - 1))
#define MMU_FLASH_MASK_FROM_VAL(PAGE_SZ) (~((PAGE_SZ) - 1))
#define MMU_DROM_END_ENTRY_VADDR_FROM_VAL(PAGE_SZ) (SOC_DRAM_FLASH_ADDRESS_HIGH - (PAGE_SZ))
/**
* MMU mapping must always be in the unit of a SPI_FLASH_MMU_PAGE_SIZE
* This macro is a helper for you to get needed page nums to be mapped. e.g.:
* Let's say SPI_FLASH_MMU_PAGE_SIZE is 64KB.
* - v_start = 0x4200_0004
* - size = 4 * 64KB
*
* You should map from 0x4200_0000, then map 5 pages.
*/
#define GET_REQUIRED_MMU_PAGES(size, v_start) ((size + (v_start - (v_start & MMU_FLASH_MASK)) + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE)
/* 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_WRSR3 0x11 /* Not all SPI flash uses this command */
#define CMD_WREN 0x06
#define CMD_WRENVSR 0x50 /* Flash write enable for volatile SR bits */
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_RDSR3 0x15 /* 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_RESUME 0x7A /* Resume command to clear flash suspend bit */
#define CMD_RESETEN 0x66
#define CMD_RESET 0x99
#define CMD_FASTRD_QIO_4B 0xEC
#define CMD_FASTRD_QUAD_4B 0x6C
#define CMD_FASTRD_DIO_4B 0xBC
#define CMD_FASTRD_DUAL_4B 0x3C
#define CMD_FASTRD_4B 0x0C
#define CMD_SLOWRD_4B 0x13
/* Provide a Flash API for bootloader_support code,
that can be used from bootloader or app code.
This header is available to source code in the bootloader &
bootloader_support components only.
*/
/**
* @brief Get number of free pages
*
* @return Number of free pages
*/
uint32_t bootloader_mmap_get_free_pages(void);
/**
* @brief Map a region of flash to data memory
*
* @important In bootloader code, only one region can be bootloader_mmaped at once. The previous region must be bootloader_munmapped before another region is mapped.
*
* @important In app code, these functions are not thread safe.
*
* Call bootloader_munmap once for each successful call to bootloader_mmap.
*
* In esp-idf app, this function maps directly to spi_flash_mmap with the @ref
* spi_flash_mmap_flag_t::SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE flag set. When XIP on PSRAM (`CONFIG_SPIRAM_XIP_FROM_PSRAM`) enabled, flash erasing/writing
* will be blocked until unmap.
*
* @param offset - Starting flash offset to map to memory.
* @param length - Length of data to map.
*
* @return Pointer to mapped data memory (at src_addr), or NULL
* if an allocation error occurred.
*/
const void *bootloader_mmap(uint32_t src_addr, uint32_t size);
/**
* @brief Unmap a previously mapped region of flash
*
* Call bootloader_munmap once for each successful call to bootloader_mmap.
*/
void bootloader_munmap(const void *mapping);
/**
* @brief Read data from Flash.
*
*
* @note All of src, dest and size have to be 4-byte aligned.
*
* @param src source address of the data in Flash.
* @param dest pointer to the destination buffer
* @param size length of data
* @param allow_decrypt If true and flash encryption is enabled, data on flash
* will be decrypted transparently as part of the read.
*
* @return ESP_OK on success, ESP_ERR_FLASH_OP_FAIL on SPI failure,
* ESP_ERR_FLASH_OP_TIMEOUT on SPI timeout.
*/
esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt);
/**
* @brief Write data to Flash.
*
* @note All of dest_addr, src and size have to be 4-byte aligned. If write_encrypted is set, dest_addr and size must be 32-byte aligned.
*
* @note In bootloader, when write_encrypted == true, the src buffer is encrypted in place.
*
* @note [ESP-TEE] Using this API from the TEE will return an error if the dest_addr lies
* within the active TEE partition range.
*
* @param dest_addr Destination address to write in Flash.
* @param src Pointer to the data to write to flash
* @param size Length of data in bytes.
* @param write_encrypted If true, data will be written encrypted on flash.
*
* @return ESP_OK on success, ESP_ERR_FLASH_OP_FAIL on SPI failure,
* ESP_ERR_FLASH_OP_TIMEOUT on SPI timeout.
*/
esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted);
/**
* @brief Erase the Flash sector.
*
* @param sector Sector number, the count starts at sector 0, 4KB per sector.
*
* @return esp_err_t
*/
esp_err_t bootloader_flash_erase_sector(size_t sector);
/**
* @brief Erase the Flash range.
*
* @note [ESP-TEE] Using this API from the TEE will return an error if the start_addr lies
* within the active TEE partition range.
*
* @param start_addr start address of flash offset
* @param size sector aligned size to be erased
*
* @return esp_err_t
*/
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t 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);
/**
* @brief Once this function is called,
* any on-going internal operations will be terminated and the device will return to its default power-on
* state and lose all the current volatile settings, such as Volatile Status Register bits, Write Enable Latch
* (WEL) status, Program/Erase Suspend status, etc.
*/
void bootloader_spi_flash_reset(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <esp_err.h>
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize spi_flash in bootloader and print flash info
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
esp_err_t bootloader_init_spi_flash(void);
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
/**
* @brief Config all flash related stuff according to the header. The consistency of all flash configs is ensured.
*
* @return None
*/
void bootloader_flash_hardware_init(void);
#endif
/**
* @brief Initialise mspi core clock
*/
void bootloader_init_mspi_clock(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Enable Quad I/O mode in bootloader (if configured)
*
* Queries attached SPI flash ID and sends correct SPI flash
* commands to enable QIO or QOUT mode, then enables this mode.
*/
void bootloader_enable_qio_mode(void);
/**
* @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);
#ifdef __cplusplus
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,502 @@
/*
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "esp32/rom/spi_flash.h"
#include "esp32/rom/cache.h"
#include "soc/efuse_reg.h"
#include "soc/spi_reg.h"
#include "soc/dport_reg.h"
#include "soc/soc_caps.h"
#include "soc/spi_pins.h"
#include "soc/chip_revision.h"
#include "hal/efuse_hal.h"
#include "hal/gpio_hal.h"
#include "hal/mmu_hal.h"
#include "flash_qio_mode.h"
#include "bootloader_common.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#define FLASH_CLK_IO MSPI_IOMUX_PIN_NUM_CLK
#define FLASH_CS_IO MSPI_IOMUX_PIN_NUM_CS0
#define FLASH_SPIQ_IO MSPI_IOMUX_PIN_NUM_MISO
#define FLASH_SPID_IO MSPI_IOMUX_PIN_NUM_MOSI
#define FLASH_SPIWP_IO MSPI_IOMUX_PIN_NUM_WP
#define FLASH_SPIHD_IO MSPI_IOMUX_PIN_NUM_HD
void bootloader_flash_update_id(void)
{
g_rom_flashchip.device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
g_rom_flashchip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config(void)
{
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
esp_rom_spiflash_config_clk(spi_clk_div, 1);
}
void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
{
uint32_t drv = 2;
if (pfhdr->spi_speed == ESP_IMAGE_SPI_SPEED_DIV_1) {
drv = 3;
}
uint32_t pkg_ver = bootloader_common_get_chip_ver_pkg();
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
// For ESP32D2WD or ESP32-PICO series,the SPI pins are already configured
// flash clock signal should come from IO MUX.
gpio_ll_func_sel(&GPIO, FLASH_CLK_IO, MSPI_FUNC_NUM);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
} else {
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
esp_rom_gpio_connect_out_signal(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPID_IO, SPID_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
//select pin function gpio
gpio_ll_func_sel(&GPIO, FLASH_SPIQ_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_SPID_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_SPIHD_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_SPIWP_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_CS_IO, PIN_FUNC_GPIO);
// flash clock signal should come from IO MUX.
gpio_ll_func_sel(&GPIO, FLASH_CLK_IO, MSPI_FUNC_NUM);
// set drive ability for clock
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
uint32_t flash_id = g_rom_flashchip.device_id;
if (flash_id == FLASH_ID_GD25LQ32C) {
// Set drive ability for 1.8v flash in 80Mhz.
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
}
}
}
}
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr)
{
int spi_cache_dummy = 0;
uint32_t modebit = READ_PERI_REG(SPI_CTRL_REG(0));
if (modebit & SPI_FASTRD_MODE) {
if (modebit & SPI_FREAD_QIO) { //SPI mode is QIO
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
} else if (modebit & SPI_FREAD_DIO) { //SPI mode is DIO
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
} else if(modebit & (SPI_FREAD_QUAD | SPI_FREAD_DUAL)) { //SPI mode is QOUT or DIO
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
}
}
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M;
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M;
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
case ESP_IMAGE_SPI_SPEED_DIV_4:
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M;
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M;
break;
default:
break;
}
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + g_rom_spiflash_dummy_len_plus[0],
SPI_USR_DUMMY_CYCLELEN_S);
}
#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD & ESP32-PICO-D4 has this GPIO wired to WP pin of flash */
#define ESP32_PICO_V3_GPIO 18 /* ESP32-PICO-V3* use this GPIO for WP pin of flash */
int bootloader_flash_get_wp_pin(void)
{
#if CONFIG_BOOTLOADER_SPI_CUSTOM_WP_PIN
return CONFIG_BOOTLOADER_SPI_WP_PIN; // can be set for bootloader when QIO or QOUT config in use
#elif CONFIG_SPIRAM_CUSTOM_SPIWP_SD3_PIN
return CONFIG_SPIRAM_SPIWP_SD3_PIN; // can be set for app when DIO or DOUT config used for PSRAM only
#else
// no custom value, find it based on the package eFuse value
switch(bootloader_common_get_chip_ver_pkg()) {
case EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH:
case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5:
return ESP32_D2WD_WP_GPIO;
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4:
/* Same package IDs are used for ESP32-PICO-V3 and ESP32-PICO-D4, silicon version differentiates */
return !ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300) ? ESP32_D2WD_WP_GPIO : ESP32_PICO_V3_GPIO;
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302:
return ESP32_PICO_V3_GPIO;
default:
return FLASH_SPIWP_IO;
}
#endif
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32");
void bootloader_configure_spi_pins(int drv)
{
uint32_t pkg_ver = bootloader_common_get_chip_ver_pkg();
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
// For ESP32D2WD or ESP32-PICO series,the SPI pins are already configured
// flash clock signal should come from IO MUX.
gpio_ll_func_sel(&GPIO, FLASH_CLK_IO, MSPI_FUNC_NUM);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
} else {
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
esp_rom_gpio_connect_out_signal(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPID_IO, SPID_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
//select pin function gpio
gpio_ll_func_sel(&GPIO, FLASH_SPIQ_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_SPID_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_SPIHD_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_SPIWP_IO, PIN_FUNC_GPIO);
gpio_ll_func_sel(&GPIO, FLASH_CS_IO, PIN_FUNC_GPIO);
// flash clock signal should come from IO MUX.
gpio_ll_func_sel(&GPIO, FLASH_CLK_IO, MSPI_FUNC_NUM);
// set drive ability for clock
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32 || CONFIG_SPIRAM_TYPE_ESPPSRAM64
uint32_t flash_id = g_rom_flashchip.device_id;
if (flash_id == FLASH_ID_GD25LQ32C) {
// Set drive ability for 1.8v flash in 80Mhz.
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
}
#endif
}
}
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
// TODO: IDF-15747 set mode
// TODO: set frequency
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_flash_gpio_config(&bootloader_image_hdr);
bootloader_flash_dummy_config(&bootloader_image_hdr);
bootloader_flash_cs_timing_config();
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
Cache_Read_Disable(0);
update_flash_config(&bootloader_image_hdr);
Cache_Flush(0);
Cache_Read_Enable(0);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(esp_rom_efuse_get_flash_gpio_info(), false);
// reset MMU
/* completely reset MMU in case serial bootloader was running */
Cache_Read_Disable(0);
#if !CONFIG_FREERTOS_UNICORE
Cache_Read_Disable(1);
#endif
Cache_Flush(0);
#if !CONFIG_FREERTOS_UNICORE
Cache_Flush(1);
#endif
mmu_init(0);
mmu_hal_config_t mmu_config = {
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
.core_nums = 1,
#else
.core_nums = SOC_CPU_CORES_NUM,
#endif
};
mmu_hal_ctx_init(&mmu_config);
#if !CONFIG_FREERTOS_UNICORE
/* The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are
necessary to work around a hardware bug. */
DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
mmu_init(1);
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
#endif
/* normal ROM boot exits with DROM0 cache unmasked,
but serial bootloader exits with it masked. */
DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
#if !CONFIG_FREERTOS_UNICORE
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
#endif
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_gpio_config(&hdr);
bootloader_flash_dummy_config(&hdr);
bootloader_flash_cs_timing_config();
/* Remaining parts in bootloader_init_spi_flash */
bootloader_flash_unlock();
Cache_Read_Disable(0);
update_flash_config(&hdr);
Cache_Flush(0);
Cache_Read_Enable(0);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,341 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp32c2/rom/spi_flash.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "soc/spi_pins.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#define FLASH_IO_MATRIX_DUMMY_40M 0
#define FLASH_IO_MATRIX_DUMMY_80M 0
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
void IRAM_ATTR bootloader_flash_set_dummy_out(void)
{
REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
}
//deprecated
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t *pfhdr)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c2");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
// IDF-4066
const uint32_t spiconfig = 0;
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
if (spiconfig == 0) {
}
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
if (hd_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
}
if (wp_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("30MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("15MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("60MHz");
break;
default:
str = ESP_LOG_ATTR_STR("15MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void bootloader_print_mmu_page_size(void)
{
mmu_page_size_t page_size = mmu_ll_get_page_size(0);
int size = (page_size == MMU_PAGE_16KB ? 16 :
page_size == MMU_PAGE_32KB ? 32 :
page_size == MMU_PAGE_64KB ? 64 : 0);
ESP_EARLY_LOGI(TAG, "MMU Page Size : %dK", size);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
bootloader_print_mmu_page_size();
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
bootloader_print_mmu_page_size();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,344 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "esp32c3/rom/spi_flash.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#define FLASH_IO_MATRIX_DUMMY_40M 0
#define FLASH_IO_MATRIX_DUMMY_80M 0
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
void IRAM_ATTR bootloader_flash_set_dummy_out(void)
{
REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
}
//deprecated
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t *pfhdr)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c3");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio();
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
if (spiconfig == 0) {
} else {
clk_gpio_num = spiconfig & 0x3f;
q_gpio_num = (spiconfig >> 6) & 0x3f;
d_gpio_num = (spiconfig >> 12) & 0x3f;
cs0_gpio_num = (spiconfig >> 18) & 0x3f;
hd_gpio_num = (spiconfig >> 24) & 0x3f;
wp_gpio_num = wp_pin;
}
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
if (hd_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
}
if (wp_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(esp_rom_efuse_get_flash_gpio_info(), false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,338 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp32c5/rom/spi_flash.h"
#include "esp32c5/rom/efuse.h"
#include "soc/io_mux_reg.h"
#include "esp_rom_efuse.h"
#include "soc/efuse_reg.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "hal/mspi_ll.h"
#include "bootloader_flash_override.h"
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_init_mspi_clock(void)
{
// Set source mspi pll clock as 80M in bootloader stage.
// SPLL clock on C5 is 480MHz , and mspi_pll needs 80MHz
// in this stage, set divider as 6
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_SPLL);
// MSPI0 and MSPI1 share this core clock register, but only setting to MSPI0 register is valid
mspi_timing_ll_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
bootloader_init_mspi_clock();
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c5");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_mspi_clock();
bootloader_init_flash_configure();
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
// Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
bootloader_spi_flash_reset();
#endif
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
// TODO: set proper dummy output
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,311 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp32c6/rom/spi_flash.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c6");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
// Since the workaround in IDF-6709, the spi_speed value in the bootloader header
// is not the real value, overwrite it.
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
bootloader_image_hdr.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_1;
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
// TODO: set proper dummy output
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,323 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp32c61/rom/spi_flash.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "hal/mspi_ll.h"
static const char *TAG __attribute__((unused)) = "boot.esp32c61";
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_init_mspi_clock(void)
{
// Set source mspi pll clock as 80M in bootloader stage.
// SPLL clock on C61 is 480MHz , and mspi_pll needs 80MHz
// in this stage, set divider as 6
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_DEFAULT);
// MSPI0 and MSPI1 share this core clock register, but only setting to MSPI0 register is valid
mspi_timing_ll_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
bootloader_init_mspi_clock();
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_mspi_clock();
bootloader_init_flash_configure();
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
// Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
bootloader_spi_flash_reset();
#endif
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
// TODO: set proper dummy output
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,315 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp32h2/rom/spi_flash.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "hal/mspi_ll.h"
#include "soc/pcr_reg.h"
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h2");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void IRAM_ATTR bootloader_flash_clock_init(void)
{
// At this moment, BBPLL should be enabled, safe to switch MSPI clock source to PLL_F64M (default clock src) to raise speed
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_PLL_F64M);
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("32MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("21.3MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("16MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("64MHz");
break;
default:
str = ESP_LOG_ATTR_STR("16MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_flash_clock_init();
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_clock_init();
// TODO: set proper dummy output
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,305 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "hal/mspi_ll.h"
#include "hal/clk_tree_ll.h"
#include "soc/pcr_reg.h"
#include "soc/spi_pins.h"
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h21");
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void IRAM_ATTR bootloader_flash_clock_init(void)
{
// To raise the MSPI clock to 64MHz, needs to enable the 64MHz clock source, which is XTAL_X2_CLK
// (FPGA image fixed MSPI0/1 clock to 64MHz)
clk_ll_xtal_x2_enable();
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_REF_F64M);
// Note: MSPI clock source cannot be set to 48MHz in bootloader
// 48MHz is derived from SPLL, and SPLL is not ready to be used in bootloader for H21
// (calibration not done since bootloader CPU clock source is also set to 64MHz, which does not rely on SPLL)
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("32MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("64MHz");
break;
default:
str = ESP_LOG_ATTR_STR("16MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_flash_clock_init();
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_clock_init();
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,312 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "rom/spi_flash.h"
#include "rom/efuse.h"
#include "soc/efuse_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "hal/mspi_ll.h"
#include "hal/clk_tree_ll.h"
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h4");
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void IRAM_ATTR bootloader_mspi_clock_init(void)
{
// To raise the MSPI clock to 64MHz, needs to enable the 64MHz clock source, which is XTAL_X2_CLK
// (FPGA image fixed MSPI0/1 clock to 64MHz)
clk_ll_xtal_x2_enable();
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_REF_F64M);
// Note: MSPI clock source cannot be set to 48MHz in bootloader
// 48MHz is derived from SPLL, and SPLL is not ready to be used in bootloader for H4
// (calibration not done since bootloader CPU clock source is also set to 64MHz, which does not rely on SPLL)
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("32MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("64MHz");
break;
default:
str = ESP_LOG_ATTR_STR("16MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_mspi_clock_init();
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_mspi_clock_init();
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,327 @@
/*
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "soc/spi_pins.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/mspi_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_private/bootloader_flash_internal.h"
void IRAM_ATTR bootloader_flash_update_id(void)
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config(void)
{
SET_PERI_REG_MASK(SPI_MEM_C_USER_REG, SPI_MEM_C_CS_HOLD_M | SPI_MEM_C_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_C_CTRL2_REG, SPI_MEM_C_CS_HOLD_TIME_V, 0, SPI_MEM_C_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_C_CTRL2_REG, SPI_MEM_C_CS_SETUP_TIME_V, 0, SPI_MEM_C_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_init_mspi_clock(void)
{
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_SPLL);
_mspi_timing_ll_set_flash_core_clock(0, 80);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
bootloader_init_mspi_clock();
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32p4");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
// Configure all Flash pins: clear pull-up/pull-down, set drive strength
// SPI CS is external pull-uped so there no need to set internal pull-up
mspi_ll_flash_pin_cfg_t flash_cfg = {
.hys = 0,
.ie = 0,
.wpu = 0,
.wpd = 0,
.drv = drv,
.reserved = 0
};
for (mspi_ll_flash_pin_id_t pin_id = MSPI_LL_PIN_ID_FLASH_CS; pin_id <= MSPI_LL_PIN_ID_FLASH_D; pin_id++) {
mspi_ll_set_flash_pin_cfg(pin_id, &flash_cfg);
}
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: IDF-15747 set mode
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_mspi_clock();
bootloader_init_flash_configure();
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
// Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
bootloader_spi_flash_reset();
#endif
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,343 @@
/*
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "esp32s2/rom/spi_flash.h"
#include "soc/efuse_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash_priv.h"
#include "bootloader_common.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#define FLASH_IO_MATRIX_DUMMY_40M 0
#define FLASH_IO_MATRIX_DUMMY_80M 0
#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3
void bootloader_flash_update_id()
{
g_rom_flashchip.device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
g_rom_flashchip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
esp_rom_spiflash_config_clk(spi_clk_div, 1);
}
void IRAM_ATTR bootloader_flash_set_dummy_out(void)
{
REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
}
//deprecated
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s2");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio();
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
if (spiconfig == 0) {
} else {
clk_gpio_num = spiconfig & 0x3f;
q_gpio_num = (spiconfig >> 6) & 0x3f;
d_gpio_num = (spiconfig >> 12) & 0x3f;
cs0_gpio_num = (spiconfig >> 18) & 0x3f;
hd_gpio_num = (spiconfig >> 24) & 0x3f;
wp_gpio_num = wp_pin;
}
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
if (hd_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
}
if (wp_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
// TODO: IDF-15747 set mode
// TODO: set frequency
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(esp_rom_efuse_get_flash_gpio_info(), false);
// init cache and mmu
bootloader_init_ext_mem();
// Workaround: normal ROM bootloader exits with DROM0 cache unmasked, but 2nd bootloader exits with it masked.
REG_CLR_BIT(EXTMEM_PRO_ICACHE_CTRL1_REG, EXTMEM_PRO_ICACHE_MASK_DROM0);
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
bootloader_flash_unlock();
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,379 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "esp32s3/rom/spi_flash.h"
#include "soc/efuse_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/spi_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_pins.h"
#include "soc/soc_caps.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash_priv.h"
#include "bootloader_common.h"
#include "bootloader_flash.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#define FLASH_IO_MATRIX_DUMMY_40M 0
#define FLASH_IO_MATRIX_DUMMY_80M 0
#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3
#define FLASH_CS_SETUP_TIME 3
#define FLASH_CS_HOLD_TIME 3
#define FLASH_CS_HOLD_DELAY 2
void bootloader_flash_update_id()
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
//SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH, so we only need to set SPI0 related registers here
if (bootloader_flash_is_octal_mode_enabled()) {
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_CS_SETUP_TIME_S);
//CS high time
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_CS_HOLD_DELAY_S);
} else {
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
}
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
esp_rom_spiflash_config_clk(spi_clk_div, 1);
}
void IRAM_ATTR bootloader_flash_set_dummy_out(void)
{
REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL);
}
//deprecated
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t *pfhdr)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s3");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio();
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
if (spiconfig == 0) {
} else {
clk_gpio_num = spiconfig & 0x3f;
q_gpio_num = (spiconfig >> 6) & 0x3f;
d_gpio_num = (spiconfig >> 12) & 0x3f;
cs0_gpio_num = (spiconfig >> 18) & 0x3f;
hd_gpio_num = (spiconfig >> 24) & 0x3f;
wp_gpio_num = wp_pin;
}
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
if (hd_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
}
if (wp_gpio_num < SOC_GPIO_PIN_COUNT) {
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
// TODO: IDF-15747 set mode
// TODO: set frequency
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = ESP_LOG_ATTR_STR("40MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = ESP_LOG_ATTR_STR("26.7MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = ESP_LOG_ATTR_STR("20MHz");
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = ESP_LOG_ATTR_STR("80MHz");
break;
default:
str = ESP_LOG_ATTR_STR("20MHz");
break;
}
ESP_EARLY_LOGI(TAG, "Boot SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = ESP_LOG_ATTR_STR("QIO");
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = ESP_LOG_ATTR_STR("QOUT");
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = ESP_LOG_ATTR_STR("DIO");
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = ESP_LOG_ATTR_STR("DOUT");
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = ESP_LOG_ATTR_STR("FAST READ");
break;
default:
str = ESP_LOG_ATTR_STR("SLOW READ");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = ESP_LOG_ATTR_STR("1MB");
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = ESP_LOG_ATTR_STR("2MB");
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = ESP_LOG_ATTR_STR("4MB");
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = ESP_LOG_ATTR_STR("8MB");
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = ESP_LOG_ATTR_STR("16MB");
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = ESP_LOG_ATTR_STR("32MB");
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = ESP_LOG_ATTR_STR("64MB");
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = ESP_LOG_ATTR_STR("128MB");
break;
default:
str = ESP_LOG_ATTR_STR("2MB");
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
// Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
bootloader_spi_flash_reset();
#endif
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
if (!bootloader_flash_is_octal_mode_enabled()) {
bootloader_enable_qio_mode();
}
#endif
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH || CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_OCTAL_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(esp_rom_efuse_get_flash_gpio_info(), false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_set_dummy_out();
bootloader_flash_cs_timing_config();
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
// Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
bootloader_spi_flash_reset();
#endif
bootloader_spi_flash_resume();
bootloader_flash_unlock();
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH || CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_OCTAL_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,327 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "soc/spi_pins.h"
#include "soc/gpio_periph.h"
#include "soc/spi_mem_reg.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_config.h"
#include "bootloader_common.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/mspi_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_private/bootloader_flash_internal.h"
void IRAM_ATTR bootloader_flash_update_id(void)
{
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
chip->device_id = bootloader_read_flash_id();
}
void bootloader_flash_update_size(uint32_t size)
{
rom_spiflash_legacy_data->chip.chip_size = size;
}
void IRAM_ATTR bootloader_flash_cs_timing_config(void)
{
SET_PERI_REG_MASK(SPI_MEM_C_USER_REG, SPI_MEM_C_CS_HOLD_M | SPI_MEM_C_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_C_CTRL2_REG, SPI_MEM_C_CS_HOLD_TIME_V, 0, SPI_MEM_C_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_C_CTRL2_REG, SPI_MEM_C_CS_SETUP_TIME_V, 0, SPI_MEM_C_CS_SETUP_TIME_S);
}
void IRAM_ATTR bootloader_init_mspi_clock(void)
{
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
_mspi_timing_ll_set_flash_core_clock(0, 80);
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_BBPLL);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
{
bootloader_init_mspi_clock();
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;
default:
break;
}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
}
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s31");
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
uint8_t clk_gpio_num = MSPI_IOMUX_PIN_NUM_CLK;
uint8_t q_gpio_num = MSPI_IOMUX_PIN_NUM_MISO;
uint8_t d_gpio_num = MSPI_IOMUX_PIN_NUM_MOSI;
uint8_t cs0_gpio_num = MSPI_IOMUX_PIN_NUM_CS0;
uint8_t hd_gpio_num = MSPI_IOMUX_PIN_NUM_HD;
uint8_t wp_gpio_num = MSPI_IOMUX_PIN_NUM_WP;
esp_rom_gpio_pad_set_drv(clk_gpio_num, drv);
esp_rom_gpio_pad_set_drv(q_gpio_num, drv);
esp_rom_gpio_pad_set_drv(d_gpio_num, drv);
esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv);
esp_rom_gpio_pad_set_drv(hd_gpio_num, drv);
esp_rom_gpio_pad_set_drv(wp_gpio_num, drv);
}
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
size = 32;
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
size = 64;
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
size = 128;
break;
default:
size = 2;
}
// Set flash chip size
esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
}
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = "40MHz";
break;
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = "26.7MHz";
break;
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = "20MHz";
break;
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = "80MHz";
break;
default:
str = "20MHz";
break;
}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = "QIO";
break;
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = "QOUT";
break;
case ESP_ROM_SPIFLASH_DIO_MODE:
str = "DIO";
break;
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = "DOUT";
break;
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = "FAST READ";
break;
default:
str = "SLOW READ";
break;
}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = "1MB";
break;
case ESP_IMAGE_FLASH_SIZE_2MB:
str = "2MB";
break;
case ESP_IMAGE_FLASH_SIZE_4MB:
str = "4MB";
break;
case ESP_IMAGE_FLASH_SIZE_8MB:
str = "8MB";
break;
case ESP_IMAGE_FLASH_SIZE_16MB:
str = "16MB";
break;
case ESP_IMAGE_FLASH_SIZE_32MB:
str = "32MB";
break;
case ESP_IMAGE_FLASH_SIZE_64MB:
str = "64MB";
break;
case ESP_IMAGE_FLASH_SIZE_128MB:
str = "128MB";
break;
default:
str = "2MB";
break;
}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_configure_spi_pins(1);
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_mspi_clock();
bootloader_init_flash_configure();
#if CONFIG_BOOTLOADER_FLASH_DC_AWARE
// Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
bootloader_spi_flash_reset();
#endif
bootloader_spi_flash_resume();
if ((void*)bootloader_flash_unlock != (void*)bootloader_flash_unlock_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_unlock");
}
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
print_flash_info(&bootloader_image_hdr);
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&bootloader_image_hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
}
esp_rom_spiflash_config_readmode(mode);
}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(0, false);
// init cache and mmu
bootloader_init_ext_mem();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
/* Alternative of bootloader_init_spi_flash */
// RAM app doesn't have headers in the flash. Make a default one for it.
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
};
bootloader_configure_spi_pins(1);
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_cs_timing_config();
bootloader_spi_flash_resume();
bootloader_flash_unlock();
#if CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
bootloader_flash_32bits_address_map_enable(bootloader_flash_get_spi_mode());
#endif
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
update_flash_config(&hdr);
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
//ensure the flash is write-protected
bootloader_enable_wp();
}
#endif //CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
@@ -0,0 +1,230 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include "bootloader_flash_config.h"
#include "flash_qio_mode.h"
#include "sdkconfig.h"
#include "bootloader_flash_priv.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_attr.h"
#include "esp_rom_spiflash.h"
#include "esp_rom_efuse.h"
#include "flash_qio_mode.h"
#include "soc/efuse_periph.h"
#include "soc/io_mux_reg.h"
#include "esp_private/spi_flash_os.h"
#include "bootloader_flash_override.h"
ESP_LOG_ATTR_TAG(TAG, "qio_mode");
/* Array of known flash chips and data to enable Quad I/O mode
Manufacturer & flash ID can be tested by running "esptool
flash-id"
If manufacturer ID matches, and flash ID ORed with flash ID mask
matches, enable_qio_mode() will execute "Read Cmd", test if bit
number "QIE Bit" is set, and if not set it will call "Write Cmd"
with this bit set.
Searching of this table stops when the first match is found.
*/
const DRAM_ATTR bootloader_qio_info_t __attribute__((weak)) bootloader_flash_qe_support_list_default[] = {
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
{ "MXIC", 0xC2, 0x2000, 0xFF00, bootloader_read_status_8b_rdsr, bootloader_write_status_8b_wrsr, 6 },
{ "ISSI", 0x9D, 0x4000, 0xCF00, bootloader_read_status_8b_rdsr, bootloader_write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
{ "WinBond", 0xEF, 0x4000, 0xFF00, bootloader_read_status_16b_rdsr_rdsr2, bootloader_write_status_16b_wrsr, 9 },
{ "GD", 0xC8, 0x6000, 0xFF00, bootloader_read_status_16b_rdsr_rdsr2, bootloader_write_status_16b_wrsr, 9 },
{ "XM25QU64A", 0x20, 0x3817, 0xFFFF, bootloader_read_status_8b_xmc25qu64a, bootloader_write_status_8b_xmc25qu64a, 6 },
{ "TH", 0xcd, 0x6000, 0xFF00, bootloader_read_status_16b_rdsr_rdsr2, bootloader_write_status_16b_wrsr, 9 },
/* Final entry is default entry, if no other IDs have matched.
This approach works for chips including:
GigaDevice (mfg ID 0xC8, flash IDs including 4016),
FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)
BY25Q32 (mfg ID 0x68, flash IDs including 4016)
*/
{ NULL, 0xFF, 0xFFFF, 0xFFFF, bootloader_read_status_8b_rdsr2, bootloader_write_status_8b_wrsr2, 1 },
};
const DRAM_ATTR bootloader_qio_info_t* bootloader_flash_qe_support_list __attribute__((weak)) = bootloader_flash_qe_support_list_default;
uint8_t DRAM_ATTR __attribute__((weak)) bootloader_flash_qe_list_count = (sizeof(bootloader_flash_qe_support_list_default) / sizeof(bootloader_qio_info_t));
static esp_err_t enable_qio_mode(bootloader_flash_read_status_fn_t read_status_fn,
bootloader_flash_write_status_fn_t write_status_fn,
uint8_t status_qio_bit);
/* Generic function to use the "user command" SPI controller functionality
to send commands to the SPI flash and read the respopnse.
The command passed here is always the on-the-wire command given to the SPI flash unit.
*/
void bootloader_enable_qio_mode(void)
{
uint32_t raw_flash_id;
uint8_t mfg_id;
uint16_t flash_id;
size_t i;
ESP_LOGD(TAG, "Probing for QIO mode enable...");
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
raw_flash_id = g_rom_flashchip.device_id;
ESP_LOGD(TAG, "Raw SPI flash chip id 0x%"PRIx32, raw_flash_id);
mfg_id = (raw_flash_id >> 16) & 0xFF;
flash_id = raw_flash_id & 0xFFFF;
ESP_LOGD(TAG, "Manufacturer ID 0x%02x chip ID 0x%04x", mfg_id, flash_id);
if ((intptr_t)bootloader_flash_qe_support_list != (intptr_t)bootloader_flash_qe_support_list_default) {
ESP_EARLY_LOGD(TAG, "Using overridden bootloader_flash_qio, the list number is %d", bootloader_flash_qe_list_count);
}
for (i = 0; i < bootloader_flash_qe_list_count - 1; i++) {
const bootloader_qio_info_t *chip = &bootloader_flash_qe_support_list[i];
if (mfg_id == chip->mfg_id && (flash_id & chip->id_mask) == (chip->flash_id & chip->id_mask)) {
ESP_LOGI(TAG, "Enabling QIO for flash chip %s", bootloader_flash_qe_support_list[i].manufacturer);
break;
}
}
if (i == bootloader_flash_qe_list_count - 1) {
ESP_LOGI(TAG, "Enabling default flash chip QIO");
}
enable_qio_mode(bootloader_flash_qe_support_list[i].read_status_fn,
bootloader_flash_qe_support_list[i].write_status_fn,
bootloader_flash_qe_support_list[i].status_qio_bit);
#if SOC_CACHE_SUPPORT_WRAP
spi_flash_wrap_probe();
spi_flash_wrap_disable();
#endif
}
static void s_flash_set_qio_pins(void)
{
#if SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE
#if CONFIG_IDF_TARGET_ESP32
esp_rom_spiflash_select_qio_pins(bootloader_flash_get_wp_pin(), esp_rom_efuse_get_flash_gpio_info());
#else
esp_rom_spiflash_select_qio_pins(esp_rom_efuse_get_flash_wp_gpio(), esp_rom_efuse_get_flash_gpio_info());
#endif // CONFIG_IDF_TARGET_ESP32
#else
// ESP32C2/ESP32C6 doesn't support configure mspi pins. So the second
// parameter is set to 0, means that chip uses default SPI pins
// and wp_gpio_num parameter(the first parameter) is ignored.
esp_rom_spiflash_select_qio_pins(0, 0);
#endif // SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE
}
static esp_err_t enable_qio_mode(bootloader_flash_read_status_fn_t read_status_fn,
bootloader_flash_write_status_fn_t write_status_fn,
uint8_t status_qio_bit)
{
uint32_t status;
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
status = read_status_fn();
ESP_LOGD(TAG, "Initial flash chip status 0x%"PRIx32, status);
if ((status & (1 << status_qio_bit)) == 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);
status = read_status_fn();
ESP_LOGD(TAG, "Updated flash chip status 0x%"PRIx32, status);
if ((status & (1 << status_qio_bit)) == 0) {
ESP_LOGE(TAG, "Failed to set QIE bit, not enabling QIO mode");
return ESP_FAIL;
}
} else {
ESP_LOGD(TAG, "QIO mode already enabled in flash");
}
ESP_LOGD(TAG, "Enabling QIO mode...");
esp_rom_spiflash_read_mode_t mode;
#if CONFIG_ESPTOOLPY_FLASHMODE_QOUT
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
#else
mode = ESP_ROM_SPIFLASH_QIO_MODE;
#endif
esp_rom_spiflash_config_readmode(mode);
s_flash_set_qio_pins();
return ESP_OK;
}
IRAM_ATTR unsigned bootloader_read_status_8b_rdsr(void)
{
return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
}
IRAM_ATTR unsigned bootloader_read_status_8b_rdsr2(void)
{
return bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8);
}
IRAM_ATTR unsigned bootloader_read_status_8b_rdsr3(void)
{
return bootloader_execute_flash_command(CMD_RDSR3, 0, 0, 8);
}
IRAM_ATTR unsigned bootloader_read_status_16b_rdsr_rdsr2(void)
{
return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
}
IRAM_ATTR void bootloader_write_status_8b_wrsr(unsigned new_status)
{
bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0);
}
IRAM_ATTR void bootloader_write_status_8b_wrsr2(unsigned new_status)
{
bootloader_execute_flash_command(CMD_WRSR2, new_status, 8, 0);
}
IRAM_ATTR void bootloader_write_status_8b_wrsr3(unsigned new_status)
{
bootloader_execute_flash_command(CMD_WRSR3, new_status, 8, 0);
}
IRAM_ATTR void bootloader_write_status_16b_wrsr(unsigned new_status)
{
bootloader_execute_flash_command(CMD_WRSR, new_status, 16, 0);
}
IRAM_ATTR unsigned bootloader_read_status_8b_xmc25qu64a(void)
{
bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
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;
}
IRAM_ATTR void bootloader_write_status_8b_xmc25qu64a(unsigned new_status)
{
bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
}