Merge branch 'feat/epi_flash_api_iram_save_4.2' into 'release/v4.2'

spi_flash: partially move API functions out of IRAM (v4.2)

See merge request espressif/esp-idf!18304
This commit is contained in:
Jiang Jiang Jian 2022-06-19 23:22:48 +08:00
commit 32aa2ab24e
34 changed files with 675 additions and 243 deletions

View File

@ -23,7 +23,7 @@
#include "unity.h"
#include "bootloader_common.h"
#include "../include_bootloader/bootloader_flash.h"
#include "../include_bootloader/bootloader_flash_priv.h"
#include "esp_log.h"
#include "esp_ota_ops.h"

View File

@ -309,6 +309,15 @@ menu "Bootloader config"
in this area of memory, you can increase it. It must be a multiple of 4 bytes.
This area (rtc_retain_mem_t) is reserved and has access from the bootloader and an application.
config BOOTLOADER_FLASH_XMC_SUPPORT
bool "Enable the support for flash chips of XMC (READ HELP FIRST)"
default y
help
Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow.
XMC chips will be forbidden to be used, when this option is disabled.
DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
endmenu # Bootloader

View File

@ -0,0 +1,61 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <esp_err.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Read flash ID by sending 0x9F command
* @return flash raw ID
* mfg_id = (ID >> 16) & 0xFF;
flash_id = ID & 0xffff;
*/
uint32_t bootloader_read_flash_id(void);
#if SOC_CACHE_SUPPORT_WRAP
/**
* @brief Set the burst mode setting command for specified wrap mode.
*
* @param mode The specified warp mode.
* @return always ESP_OK
*/
esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode);
#endif
/**
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
*
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
*/
esp_err_t bootloader_flash_xmc_startup(void);
/**
* @brief Unlock Flash write protect.
* Please do not call this function in SDK.
*
* @note This can be overridden because it's attribute weak.
*/
esp_err_t bootloader_flash_unlock(void);
#ifdef __cplusplus
}
#endif

View File

@ -19,11 +19,28 @@
#include <stdint.h>
#include <esp_err.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#include "sdkconfig.h"
#include "bootloader_flash.h"
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_BLOCK_SIZE 0x10000
#define MMAP_ALIGNED_MASK 0x0000FFFF
/* SPI commands (actual on-wire commands not SPI controller bitmasks)
Suitable for use with the bootloader_execute_flash_command static function.
*/
#define CMD_RDID 0x9F
#define CMD_WRSR 0x01
#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */
#define CMD_WREN 0x06
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
#define CMD_WRAP 0x77 /* Set burst with wrap command */
/* Provide a Flash API for bootloader_support code,
that can be used from bootloader or app code.
@ -136,4 +153,29 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad
return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) / MMU_BLOCK_SIZE;
}
/**
* @brief Execute a user command on the flash
*
* @param command The command value to execute.
* @param mosi_data MOSI data to send
* @param mosi_len Length of MOSI data, in bits
* @param miso_len Length of MISO data to receive, in bits
* @return Received MISO data
*/
uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
/**
* @brief Read the SFDP of the flash
*
* @param sfdp_addr Address of the parameter to read
* @param miso_byte_num Bytes to read
* @return The read SFDP, little endian, 4 bytes at most
*/
uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
/**
* @brief Enable the flash write protect (WEL bit).
*/
void bootloader_enable_wp(void);
#endif

View File

@ -13,6 +13,8 @@
// limitations under the License.
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -28,7 +28,7 @@
#include "esp32s2/rom/gpio.h"
#endif
#include "esp_flash_partitions.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_common.h"
#include "bootloader_utility.h"
#include "soc/gpio_periph.h"

View File

@ -13,13 +13,44 @@
// limitations under the License.
#include <stddef.h>
#include <bootloader_flash.h>
#include <bootloader_flash_priv.h>
#include <esp_log.h>
#include <esp_flash_encrypt.h>
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if CONFIG_IDF_TARGET_ESP32
# include "soc/spi_struct.h"
# include "soc/spi_reg.h"
/* SPI flash controller */
# define SPIFLASH SPI1
#else
# include "soc/spi_mem_struct.h"
# include "soc/spi_mem_reg.h"
/* SPI flash controller */
# define SPIFLASH SPIMEM1
#endif
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/spi_flash.h"
#include "esp32/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h" //For SPI_Encrypt_Write
#include "esp32s2/rom/ets_sys.h"
#endif
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
#define ISSI_ID 0x9D
#define MXIC_ID 0xC2
#define GD_Q_ID_HIGH 0xC8
#define GD_Q_ID_MID 0x40
#define GD_Q_ID_LOW 0x16
#define ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
#define ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2 BIT1 // QE position when you write 8 bits(for SR2) at one time.
#define ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE BIT9 // QE position when you write 16 bits at one time.
#ifndef BOOTLOADER_BUILD
/* Normal app version maps to esp_spi_flash.h operations...
*/
@ -89,7 +120,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
return spi_flash_erase_range(start_addr, size);
}
#else
#else //BOOTLOADER_BUILD
/* Bootloader version, uses ROM functions only */
#include "soc/dport_reg.h"
#if CONFIG_IDF_TARGET_ESP32
@ -318,7 +349,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
return ESP_FAIL;
}
err = spi_to_esp_err(esp_rom_spiflash_unlock());
err = bootloader_flash_unlock();
if (err != ESP_OK) {
return err;
}
@ -364,4 +395,332 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
}
return spi_to_esp_err(rc);
}
#endif // BOOTLOADER_BUILD
FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == ISSI_ID;
}
// For GD25Q32, GD25Q64, GD25Q127C, GD25Q128, which use single command to read/write different SR.
FORCE_INLINE_ATTR bool is_gd_q_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == GD_Q_ID_HIGH && BYTESHIFT(chip->device_id, 1) == GD_Q_ID_MID && BYTESHIFT(chip->device_id, 0) >= GD_Q_ID_LOW;
}
FORCE_INLINE_ATTR bool is_mxic_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == MXIC_ID;
}
esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void)
{
// At the beginning status == new_status == status_sr2 == new_status_sr2 == 0.
// If the register doesn't need to be updated, keep them the same (0), so that no command will be actually sent.
uint16_t status = 0; // status for SR1 or SR1+SR2 if writing SR with 01H + 2Bytes.
uint16_t new_status = 0;
uint8_t status_sr2 = 0; // status_sr2 for SR2.
uint8_t new_status_sr2 = 0;
uint8_t sr1_bit_num = 0;
esp_err_t err = ESP_OK;
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
if (is_issi_chip(&g_rom_flashchip) || is_mxic_chip(&g_rom_flashchip)) {
// Currently ISSI & MXIC share the same command and register layout, which is different from the default model.
// If any code here needs to be modified, check both chips.
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
/* Clear all bits in the mask.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
sr1_bit_num = 8;
new_status = status & (~ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI);
} else if (is_gd_q_chip(&g_rom_flashchip)) {
/* The GD chips behaviour is to clear all bits in SR1 and clear bits in SR2 except QE bit.
Use 01H to write SR1 and 31H to write SR2.
*/
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
sr1_bit_num = 8;
new_status = 0;
status_sr2 = bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8);
new_status_sr2 = status_sr2 & ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2;
} else {
/* For common behaviour, like XMC chips, Use 01H+2Bytes to write both SR1 and SR2*/
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
/* Clear all bits except QE, if it is set.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
sr1_bit_num = 16;
new_status = status & ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE;
}
// When SR is written, set to true to indicate that WRDI need to be sent to ensure the protection is ON before return.
bool status_written = false;
// Skip if nothing needs to be changed. Meaningless writing to SR increases the risk during write and wastes time.
if (status != new_status) {
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
bootloader_execute_flash_command(CMD_WRSR, new_status, sr1_bit_num, 0);
status_written = true;
}
if (status_sr2 != new_status_sr2) {
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
bootloader_execute_flash_command(CMD_WRSR2, new_status_sr2, 8, 0);
status_written = true;
}
if (status_written) {
//Call esp_rom_spiflash_wait_idle to make sure previous WRSR is completed.
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);
}
return err;
}
/* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[];
IRAM_ATTR static uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len)
{
assert(mosi_len <= 32);
assert(miso_len <= 32);
uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
uint32_t old_user_reg = SPIFLASH.user.val;
uint32_t old_user1_reg = SPIFLASH.user1.val;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
#else
SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
#endif
//command phase
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = command;
//addr phase
SPIFLASH.user.usr_addr = addr_len > 0;
SPIFLASH.user1.usr_addr_bitlen = addr_len - 1;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.addr = (addr_len > 0)? (address << (32-addr_len)) : 0;
#else
SPIFLASH.addr = address;
#endif
//dummy phase
if (miso_len > 0) {
uint32_t total_dummy = dummy_len + g_rom_spiflash_dummy_len_plus[1];
SPIFLASH.user.usr_dummy = total_dummy > 0;
SPIFLASH.user1.usr_dummy_cyclelen = total_dummy - 1;
} else {
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user1.usr_dummy_cyclelen = 0;
}
//output data
SPIFLASH.user.usr_mosi = mosi_len > 0;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
#else
SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
#endif
SPIFLASH.data_buf[0] = mosi_data;
//input data
SPIFLASH.user.usr_miso = miso_len > 0;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
#else
SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
#endif
SPIFLASH.cmd.usr = 1;
while (SPIFLASH.cmd.usr != 0) {
}
SPIFLASH.ctrl.val = old_ctrl_reg;
SPIFLASH.user.val = old_user_reg;
SPIFLASH.user1.val = old_user1_reg;
uint32_t ret = SPIFLASH.data_buf[0];
if (miso_len < 32) {
//set unused bits to 0
ret &= ~(UINT32_MAX << miso_len);
}
return ret;
}
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{
const uint8_t addr_len = 0;
const uint8_t address = 0;
const uint8_t dummy_len = 0;
return bootloader_flash_execute_command_common(command, addr_len, address,
dummy_len, mosi_len, mosi_data, miso_len);
}
// cmd(0x5A) + 24bit address + 8 cycles dummy
uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
{
assert(miso_byte_num <= 4);
const uint8_t command = CMD_RDSFDP;
const uint8_t addr_len = 24;
const uint8_t dummy_len = 8;
const uint8_t mosi_len = 0;
const uint32_t mosi_data = 0;
const uint8_t miso_len = miso_byte_num * 8;
return bootloader_flash_execute_command_common(command, addr_len, sfdp_addr,
dummy_len, mosi_len, mosi_data, miso_len);
}
void bootloader_enable_wp(void)
{
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
}
uint32_t IRAM_ATTR bootloader_read_flash_id(void)
{
uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
return id;
}
#if SOC_CACHE_SUPPORT_WRAP
esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
{
uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val;
uint32_t reg_bkp_usr = SPIFLASH.user.val;
SPIFLASH.user.fwrite_dio = 0;
SPIFLASH.user.fwrite_dual = 0;
SPIFLASH.user.fwrite_qio = 1;
SPIFLASH.user.fwrite_quad = 0;
SPIFLASH.ctrl.fcmd_dual = 0;
SPIFLASH.ctrl.fcmd_quad = 0;
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user.usr_addr = 1;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = CMD_WRAP;
SPIFLASH.user1.usr_addr_bitlen = 23;
SPIFLASH.addr = 0;
SPIFLASH.user.usr_miso = 0;
SPIFLASH.user.usr_mosi = 1;
SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7;
SPIFLASH.data_buf[0] = (uint32_t) mode << 4;;
SPIFLASH.cmd.usr = 1;
while(SPIFLASH.cmd.usr != 0)
{ }
SPIFLASH.ctrl.val = reg_bkp_ctrl;
SPIFLASH.user.val = reg_bkp_usr;
return ESP_OK;
}
#endif //SOC_CACHE_SUPPORT_WRAP
/*******************************************************************************
* XMC startup flow
******************************************************************************/
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
#define XMC_VENDOR_ID 0x20
#if BOOTLOADER_BUILD
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_LOG##level(TAG, ##__VA_ARGS__)
#else
static DRAM_ATTR char bootloader_flash_tag[] = "bootloader_flash";
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_DRAM_LOG##level(bootloader_flash_tag, ##__VA_ARGS__)
#endif
#if XMC_SUPPORT
//strictly check the model
static IRAM_ATTR bool is_xmc_chip_strict(uint32_t rdid)
{
uint32_t vendor_id = BYTESHIFT(rdid, 2);
uint32_t mfid = BYTESHIFT(rdid, 1);
uint32_t cpid = BYTESHIFT(rdid, 0);
if (vendor_id != XMC_VENDOR_ID) {
return false;
}
bool matched = false;
if (mfid == 0x40) {
if (cpid >= 0x13 && cpid <= 0x20) {
matched = true;
}
} else if (mfid == 0x41) {
if (cpid >= 0x17 && cpid <= 0x20) {
matched = true;
}
} else if (mfid == 0x50) {
if (cpid >= 0x15 && cpid <= 0x16) {
matched = true;
}
}
return matched;
}
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
{
// If the RDID value is a valid XMC one, may skip the flow
const bool fast_check = true;
if (fast_check && is_xmc_chip_strict(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(D, "XMC chip detected by RDID (%08X), skip.", g_rom_flashchip.device_id);
return ESP_OK;
}
// Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow
const int sfdp_mfid_addr = 0x10;
uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff);
if (mf_id != XMC_VENDOR_ID) {
BOOTLOADER_FLASH_LOG(D, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id);
return ESP_OK;
}
BOOTLOADER_FLASH_LOG(I, "XM25QHxxC startup flow");
// Enter DPD
bootloader_execute_flash_command(0xB9, 0, 0, 0);
// Enter UDPD
bootloader_execute_flash_command(0x79, 0, 0, 0);
// Exit UDPD
bootloader_execute_flash_command(0xFF, 0, 0, 0);
// Delay tXUDPD
ets_delay_us(2000);
// Release Power-down
bootloader_execute_flash_command(0xAB, 0, 0, 0);
ets_delay_us(20);
// Read flash ID and check again
g_rom_flashchip.device_id = bootloader_read_flash_id();
if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(E, "XMC flash startup fail");
return ESP_FAIL;
}
return ESP_OK;
}
#else
//only compare the vendor id
static IRAM_ATTR bool is_xmc_chip(uint32_t rdid)
{
uint32_t vendor_id = (rdid >> 16) & 0xFF;
return (vendor_id == XMC_VENDOR_ID);
}
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
{
if (is_xmc_chip(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(E, "XMC chip detected (%08X) while support disabled.", g_rom_flashchip.device_id);
return ESP_FAIL;
}
return ESP_OK;
}
#endif //XMC_SUPPORT

View File

@ -17,7 +17,7 @@
#include "esp_attr.h"
#include "esp_log.h"
#include "bootloader_init.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_flash_config.h"
#include "bootloader_random.h"
#include "bootloader_clock.h"

View File

@ -59,7 +59,7 @@
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "bootloader_config.h"
#include "bootloader_common.h"

View File

@ -23,6 +23,7 @@
#include "bootloader_common.h"
#include "bootloader_flash_config.h"
#include "bootloader_mem.h"
#include "bootloader_flash_priv.h"
#include "soc/cpu.h"
#include "soc/dport_reg.h"
@ -259,7 +260,7 @@ static esp_err_t bootloader_init_spi_flash(void)
}
#endif
esp_rom_spiflash_unlock();
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
@ -267,6 +268,8 @@ static esp_err_t bootloader_init_spi_flash(void)
print_flash_info(&bootloader_image_hdr);
update_flash_config(&bootloader_image_hdr);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
@ -452,6 +455,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -14,7 +14,7 @@
#include <strings.h>
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "esp_image_format.h"
#include "esp_flash_encrypt.h"
#include "esp_flash_partitions.h"

View File

@ -29,7 +29,7 @@
#include "sdkconfig.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"

View File

@ -13,7 +13,7 @@
// limitations under the License.
#include "sdkconfig.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_log.h"

View File

@ -26,6 +26,7 @@
#include "bootloader_clock.h"
#include "bootloader_flash_config.h"
#include "bootloader_mem.h"
#include "bootloader_flash_priv.h"
#include "esp32s2/rom/cache.h"
#include "esp32s2/rom/ets_sys.h"
@ -205,7 +206,7 @@ static esp_err_t bootloader_init_spi_flash(void)
}
#endif
esp_rom_spiflash_unlock();
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
@ -213,6 +214,8 @@ static esp_err_t bootloader_init_spi_flash(void)
print_flash_info(&bootloader_image_hdr);
update_flash_config(&bootloader_image_hdr);
//ensure the flash is write-protected
bootloader_enable_wp();
return ESP_OK;
}
@ -374,6 +377,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -14,7 +14,7 @@
#include <strings.h>
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "bootloader_utility.h"
#include "esp_image_format.h"
@ -303,8 +303,8 @@ static esp_err_t encrypt_bootloader(void)
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
}
}
ESP_LOGI(TAG, "bootloader encrypted successfully");
return err;
}

View File

@ -17,7 +17,7 @@
#include "esp_secure_boot.h"
#include "soc/efuse_reg.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"

View File

@ -15,7 +15,7 @@
#include <string.h>
#include "esp_fault.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_log.h"

View File

@ -20,7 +20,7 @@
#include <esp_log.h>
#include <esp_attr.h>
#include <esp_spi_flash.h>
#include <bootloader_flash.h>
#include <bootloader_flash_priv.h>
#include <bootloader_random.h>
#include <bootloader_sha.h>
#include "bootloader_util.h"

View File

@ -15,6 +15,7 @@
#include <stdint.h>
#include "bootloader_flash_config.h"
#include "flash_qio_mode.h"
#include "bootloader_flash_priv.h"
#include "esp_log.h"
#include "esp_err.h"
#if CONFIG_IDF_TARGET_ESP32
@ -25,30 +26,10 @@
#include "esp32s2/rom/efuse.h"
#include "soc/spi_mem_struct.h"
#endif
#include "soc/spi_struct.h"
#include "soc/spi_reg.h"
#include "soc/efuse_periph.h"
#include "soc/io_mux_reg.h"
#include "sdkconfig.h"
/* SPI flash controller */
#if CONFIG_IDF_TARGET_ESP32
#define SPIFLASH SPI1
#elif CONFIG_IDF_TARGET_ESP32S2
#define SPIFLASH SPIMEM1
#endif
/* SPI commands (actual on-wire commands not SPI controller bitmasks)
Suitable for use with the execute_flash_command static function.
*/
#define CMD_RDID 0x9F
#define CMD_WRSR 0x01
#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */
#define CMD_WREN 0x06
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
static const char *TAG = "qio_mode";
@ -126,56 +107,6 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,
The command passed here is always the on-the-wire command given to the SPI flash unit.
*/
static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
/* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[];
uint32_t bootloader_read_flash_id(void)
{
uint32_t id = execute_flash_command(CMD_RDID, 0, 0, 24);
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
return id;
}
#if CONFIG_IDF_TARGET_ESP32S2
#define FLASH_WRAP_CMD 0x77
typedef enum {
FLASH_WRAP_MODE_8B = 0,
FLASH_WRAP_MODE_16B = 2,
FLASH_WRAP_MODE_32B = 4,
FLASH_WRAP_MODE_64B = 6,
FLASH_WRAP_MODE_DISABLE = 1
} spi_flash_wrap_mode_t;
static esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode)
{
uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val;
uint32_t reg_bkp_usr = SPIFLASH.user.val;
SPIFLASH.user.fwrite_dio = 0;
SPIFLASH.user.fwrite_dual = 0;
SPIFLASH.user.fwrite_qio = 1;
SPIFLASH.user.fwrite_quad = 0;
SPIFLASH.ctrl.fcmd_dual = 0;
SPIFLASH.ctrl.fcmd_quad = 0;
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user.usr_addr = 1;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD;
SPIFLASH.user1.usr_addr_bitlen = 23;
SPIFLASH.addr = 0;
SPIFLASH.user.usr_miso = 0;
SPIFLASH.user.usr_mosi = 1;
SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7;
SPIFLASH.data_buf[0] = (uint32_t) mode << 4;;
SPIFLASH.cmd.usr = 1;
while (SPIFLASH.cmd.usr != 0) {
}
SPIFLASH.ctrl.val = reg_bkp_ctrl;
SPIFLASH.user.val = reg_bkp_usr;
return ESP_OK;
}
#endif
void bootloader_enable_qio_mode(void)
{
@ -208,8 +139,8 @@ void bootloader_enable_qio_mode(void)
enable_qio_mode(chip_data[i].read_status_fn,
chip_data[i].write_status_fn,
chip_data[i].status_qio_bit);
#if CONFIG_IDF_TARGET_ESP32S2
spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
#if SOC_CACHE_SUPPORT_WRAP
bootloader_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
#endif
}
@ -226,7 +157,7 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,
ESP_LOGD(TAG, "Initial flash chip status 0x%x", status);
if ((status & (1 << status_qio_bit)) == 0) {
execute_flash_command(CMD_WREN, 0, 0, 0);
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
write_status_fn(status | (1 << status_qio_bit));
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
@ -264,95 +195,48 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,
static unsigned read_status_8b_rdsr(void)
{
return execute_flash_command(CMD_RDSR, 0, 0, 8);
return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
}
static unsigned read_status_8b_rdsr2(void)
{
return execute_flash_command(CMD_RDSR2, 0, 0, 8);
return bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8);
}
static unsigned read_status_16b_rdsr_rdsr2(void)
{
return execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
}
static void write_status_8b_wrsr(unsigned new_status)
{
execute_flash_command(CMD_WRSR, new_status, 8, 0);
bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0);
}
static void write_status_8b_wrsr2(unsigned new_status)
{
execute_flash_command(CMD_WRSR2, new_status, 8, 0);
bootloader_execute_flash_command(CMD_WRSR2, new_status, 8, 0);
}
static void write_status_16b_wrsr(unsigned new_status)
{
execute_flash_command(CMD_WRSR, new_status, 16, 0);
bootloader_execute_flash_command(CMD_WRSR, new_status, 16, 0);
}
static unsigned read_status_8b_xmc25qu64a(void)
{
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
uint32_t read_status = execute_flash_command(CMD_RDSR, 0, 0, 8);
execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
uint32_t read_status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
return read_status;
}
static void write_status_8b_xmc25qu64a(unsigned new_status)
{
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WRSR, new_status, 8, 0);
bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
}
static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{
uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
#elif CONFIG_IDF_TARGET_ESP32S2
SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
#endif
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user.usr_addr = 0;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = command;
SPIFLASH.user.usr_miso = miso_len > 0;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
#elif CONFIG_IDF_TARGET_ESP32S2
SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
#endif
SPIFLASH.user.usr_mosi = mosi_len > 0;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
#elif CONFIG_IDF_TARGET_ESP32S2
SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
#endif
SPIFLASH.data_buf[0] = mosi_data;
if (g_rom_spiflash_dummy_len_plus[1]) {
/* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
if (miso_len > 0) {
SPIFLASH.user.usr_dummy = 1;
SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
} else {
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user1.usr_dummy_cyclelen = 0;
}
}
SPIFLASH.cmd.usr = 1;
while (SPIFLASH.cmd.usr != 0) {
}
SPIFLASH.ctrl.val = old_ctrl_reg;
return SPIFLASH.data_buf[0];
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "bootloader_sha.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include <stdbool.h>
#include <string.h>
#include <assert.h>

View File

@ -13,7 +13,7 @@
// limitations under the License.
#include "sdkconfig.h"
#include "bootloader_flash.h"
#include "bootloader_flash_priv.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "esp_log.h"
@ -325,7 +325,7 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
break;
}
}
free(sig_be);
free(buf);
#if CONFIG_IDF_TARGET_ESP32

View File

@ -48,7 +48,7 @@ void esp_efuse_reset(void)
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
#include "../include_bootloader/bootloader_flash.h"
#include "../include_bootloader/bootloader_flash_priv.h"
#include "esp_flash_encrypt.h"
static uint32_t esp_efuse_flash_offset = 0;

View File

@ -70,6 +70,7 @@
#include "esp_ota_ops.h"
#include "esp_efuse.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash.h"
#include "bootloader_mem.h"
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
@ -439,7 +440,7 @@ void start_cpu0_default(void)
extern void esp_rom_spiflash_attach(uint32_t, bool);
esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false);
esp_rom_spiflash_unlock();
bootloader_flash_unlock();
#else
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
// the binary header through cache by accessing SOC_DROM_LOW address.

View File

@ -121,6 +121,7 @@ extern "C" {
#define ESP_ROM_SPIFLASH_BP2 BIT4
#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2)
#define ESP_ROM_SPIFLASH_QE BIT9
#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
//Extra dummy for flash read
#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0
@ -259,7 +260,7 @@ esp_rom_spiflash_result_t esp_rom_spiflash_read_status(esp_rom_spiflash_chip_t *
esp_rom_spiflash_result_t esp_rom_spiflash_read_statushigh(esp_rom_spiflash_chip_t *spi, uint32_t *status);
/**
* @brief Write status to Falsh status register.
* @brief Write status to Flash status register.
* Please do not call this function in SDK.
*
* @param esp_rom_spiflash_chip_t *spi : The information for Flash, which is exported from ld file.

View File

@ -9,6 +9,8 @@
#define SOC_CPU_CORES_NUM 1
#define SOC_SUPPORTS_SECURE_DL_MODE 1
#define SOC_CACHE_SUPPORT_WRAP 1
/*--------------- PHY REGISTER AND MEMORY SIZE CAPS --------------------------*/
#define SOC_PHY_DIG_REGS_MEM_SIZE (21*4)

View File

@ -1,5 +1,3 @@
set(priv_requires bootloader_support soc)
if(BOOTLOADER_BUILD)
if (CONFIG_IDF_TARGET_ESP32)
# ESP32 Bootloader needs SPIUnlock from this file, but doesn't
@ -10,6 +8,7 @@ if(BOOTLOADER_BUILD)
set(srcs)
endif()
set(cache_srcs "")
set(priv_requires bootloader_support soc)
else()
set(cache_srcs
"cache_utils.c"

View File

@ -49,8 +49,9 @@ menu "SPI Flash driver"
default y
help
Enable this flag to use patched versions of SPI flash ROM driver functions.
This option is needed to write to flash on ESP32-D2WD, and any configuration
where external SPI flash is connected to non-default pins.
This option should be enabled, if any one of the following is true: (1) need to write
to flash on ESP32-D2WD; (2) main SPI flash is connected to non-default pins; (3) main
SPI flash chip is manufactured by ISSI.
choice SPI_FLASH_DANGEROUS_WRITE
bool "Writing to dangerous flash regions"

View File

@ -21,8 +21,14 @@
#define SPI_IDX 1
#define OTH_IDX 0
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip;
static inline bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
{
return (((chip->device_id >> 16)&0xff) == 0x9D);
}
esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi)
{
uint32_t status;
@ -58,28 +64,46 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp
about interrupts, CPU coordination, flash mapping. However some of
the functions in esp_spi_flash.c call it.
*/
esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void)
__attribute__((__unused__)) esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void)
{
uint32_t status;
uint32_t new_status;
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}
if (is_issi_chip(&g_rom_spiflash_chip)) {
// ISSI chips have different QE position
/* Clear all bits except QIE, if it is set.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
status &= ESP_ROM_SPIFLASH_QE;
if (esp_rom_spiflash_read_status(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}
/* Clear all bits in the mask.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
new_status = status & (~ESP_ROM_SPIFLASH_BP_MASK_ISSI);
// Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing.
if (new_status == status) return ESP_ROM_SPIFLASH_RESULT_OK;
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
} else {
if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}
/* Clear all bits except QE, if it is set.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
new_status = status & ESP_ROM_SPIFLASH_QE;
SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
}
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN);
while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) {
}
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, status) != ESP_ROM_SPIFLASH_RESULT_OK) {
if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, new_status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}

View File

@ -20,6 +20,7 @@
#include "soc/soc_memory_layout.h"
#include "esp32s2/rom/spi_flash.h"
#include "esp32s2/rom/cache.h"
#include "bootloader_flash.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash.h"
#include "esp_log.h"
@ -78,48 +79,22 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a
}
}
#define FLASH_WRAP_CMD 0x77
esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode)
{
uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val;
uint32_t reg_bkp_usr = SPIFLASH.user.val;
SPIFLASH.user.fwrite_dio = 0;
SPIFLASH.user.fwrite_dual = 0;
SPIFLASH.user.fwrite_qio = 1;
SPIFLASH.user.fwrite_quad = 0;
SPIFLASH.ctrl.fcmd_dual = 0;
SPIFLASH.ctrl.fcmd_quad = 0;
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user.usr_addr = 1;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD;
SPIFLASH.user1.usr_addr_bitlen = 23;
SPIFLASH.addr = 0;
SPIFLASH.user.usr_miso = 0;
SPIFLASH.user.usr_mosi = 1;
SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7;
SPIFLASH.data_buf[0] = (uint32_t) mode << 4;;
SPIFLASH.cmd.usr = 1;
while(SPIFLASH.cmd.usr != 0)
{ }
SPIFLASH.ctrl.val = reg_bkp_ctrl;
SPIFLASH.user.val = reg_bkp_usr;
return ESP_OK;
return bootloader_flash_wrap_set(mode);
}
esp_err_t spi_flash_enable_wrap(uint32_t wrap_size)
{
switch(wrap_size) {
case 8:
return spi_flash_wrap_set(FLASH_WRAP_MODE_8B);
return bootloader_flash_wrap_set(FLASH_WRAP_MODE_8B);
case 16:
return spi_flash_wrap_set(FLASH_WRAP_MODE_16B);
return bootloader_flash_wrap_set(FLASH_WRAP_MODE_16B);
case 32:
return spi_flash_wrap_set(FLASH_WRAP_MODE_32B);
return bootloader_flash_wrap_set(FLASH_WRAP_MODE_32B);
case 64:
return spi_flash_wrap_set(FLASH_WRAP_MODE_64B);
return bootloader_flash_wrap_set(FLASH_WRAP_MODE_64B);
default:
return ESP_FAIL;
}
@ -127,7 +102,7 @@ esp_err_t spi_flash_enable_wrap(uint32_t wrap_size)
void spi_flash_disable_wrap(void)
{
spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
bootloader_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
}
bool spi_flash_support_wrap_size(uint32_t wrap_size)

View File

@ -502,7 +502,27 @@ esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_
return spiflash_end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
static esp_err_t NOINLINE_ATTR IRAM_ATTR flash_read_core(esp_flash_t *chip, void* buffer_to_read, uint32_t address, uint32_t length_to_read, bool *out_read_success)
{
esp_err_t err = ESP_OK;
bool read_success = false;
read_success = false;
err = spiflash_start(chip);
if (err == ESP_OK) {
err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read);
}
if (err == ESP_OK) {
read_success = true;
}
err = spiflash_end(chip, err);
*out_read_success = read_success;
return err;
}
esp_err_t esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
{
if (length == 0) {
return ESP_OK;
@ -543,28 +563,17 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
esp_err_t err = ESP_OK;
do {
err = spiflash_start(chip);
if (err != ESP_OK) {
break;
}
//if required (dma buffer allocated), read to the buffer instead of the original buffer
uint8_t* buffer_to_read = (temp_buffer)? temp_buffer : buffer;
// Length we will read this iteration is either the chunk size or the remaining length, whichever is smaller
size_t length_to_read = MIN(read_chunk_size, length);
if (err == ESP_OK) {
err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read);
}
if (err != ESP_OK) {
spiflash_end(chip, err);
break;
}
//even if this is failed, the data is still valid, copy before quit
err = spiflash_end(chip, err);
bool read_success;
err = flash_read_core(chip, buffer_to_read, address, length_to_read, &read_success);
//copy back to the original buffer
if (temp_buffer) {
if (read_success && temp_buffer) {
memcpy(buffer, temp_buffer, length_to_read);
}
address += length_to_read;
@ -576,7 +585,28 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
return err;
}
esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
// This function disable the cache, but when returning from this function, the cache should be enabled.
static esp_err_t IRAM_ATTR NOINLINE_ATTR flash_write_core(esp_flash_t *chip,
const void* write_buf, uint32_t write_addr, uint32_t write_len,
uint32_t address, uint32_t length, bool final)
{
bool bus_acquire = false; //controls whether the flash_end_flush_cache() needs to disable the cache again.
esp_err_t err = spiflash_start(chip);
if (err == ESP_OK) {
bus_acquire = true;
err = chip->chip_drv->write(chip, write_buf, write_addr, write_len);
}
if (bus_acquire) {
//on IDF v4.2, the flush is done in chip driver layer. Call spiflash_end() here.
err = spiflash_end(chip, err);
}
return err;
}
esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
if (length == 0) {
return ESP_OK;
@ -595,31 +625,32 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
by artificially cutting into MAX_WRITE_CHUNK parts (in an OS
environment, this prevents writing from causing interrupt or higher priority task
starvation.) */
uint32_t write_addr = address;
uint32_t len_remain = length;
do {
uint32_t write_len;
const void *write_buf;
uint32_t temp_buf[8];
if (direct_write) {
write_len = MIN(length, MAX_WRITE_CHUNK);
write_len = MIN(len_remain, MAX_WRITE_CHUNK);
write_buf = buffer;
} else {
write_len = MIN(length, sizeof(temp_buf));
write_len = MIN(len_remain, sizeof(temp_buf));
memcpy(temp_buf, buffer, write_len);
write_buf = temp_buf;
}
err = spiflash_start(chip);
if (err != ESP_OK) {
return err;
bool final = (len_remain == write_len);
//This function ensures cache enabled when returned
err = flash_write_core(chip, write_buf, write_addr, write_len, address, length, final);
if (err != ESP_OK || final) {
break;
}
err = chip->chip_drv->write(chip, write_buf, address, write_len);
address += write_len;
len_remain -= write_len;
assert(len_remain < length);
write_addr += write_len;
buffer = (void *)((intptr_t)buffer + write_len);
length -= write_len;
err = spiflash_end(chip, err);
} while (err == ESP_OK && length > 0);
return err;
}

View File

@ -36,14 +36,13 @@
#include "esp32s2/rom/spi_flash.h"
#include "esp32s2/rom/cache.h"
#include "esp32s2/clk.h"
#include "soc/spi_mem_reg.h"
#include "soc/spi_mem_struct.h"
#endif
#include "esp_flash_partitions.h"
#include "cache_utils.h"
#include "esp_flash.h"
#include "esp_attr.h"
#include "esp_timer.h"
#include "bootloader_flash.h"
esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size);
@ -201,11 +200,8 @@ static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(void)
static bool unlocked = false;
if (!unlocked) {
spi_flash_guard_start();
esp_rom_spiflash_result_t rc = esp_rom_spiflash_unlock();
bootloader_flash_unlock();
spi_flash_guard_end();
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
return rc;
}
unlocked = true;
}
return ESP_ROM_SPIFLASH_RESULT_OK;
@ -833,6 +829,7 @@ void spi_flash_dump_counters(void)
#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
#if defined(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) && defined(CONFIG_IDF_TARGET_ESP32S2)
// TODO esp32s2: Remove once ESP32S2 has new SPI Flash API support
esp_flash_t *esp_flash_default_chip = NULL;

View File

@ -75,6 +75,11 @@ extern "C" int spi_flash_get_erase_cycles(size_t sector)
return spiflash.get_erase_cycles(sector);
}
extern "C" esp_err_t bootloader_flash_unlock(void)
{
return ESP_OK;
}
esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t target, uint32_t *dest, int32_t len)
{
return spiflash.read(target, dest, len);

View File

@ -12,6 +12,8 @@
#include "test_utils.h"
#include "ccomp_timer.h"
#include "esp_log.h"
#include "bootloader_flash.h" //for bootloader_flash_xmc_startup
struct flash_test_ctx {
uint32_t offset;
@ -372,3 +374,22 @@ TEST_CASE("spi_flash deadlock with high priority busy-waiting task", "[spi_flash
TEST_ASSERT_EQUAL_INT(uxTaskPriorityGet(NULL), UNITY_FREERTOS_PRIORITY);
}
#endif // portNUM_PROCESSORS > 1
static IRAM_ATTR NOINLINE_ATTR void test_xmc_startup(void)
{
extern void spi_flash_disable_interrupts_caches_and_other_cpu(void);
extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
esp_err_t ret = ESP_OK;
spi_flash_disable_interrupts_caches_and_other_cpu();
ret = bootloader_flash_xmc_startup();
spi_flash_enable_interrupts_caches_and_other_cpu();
TEST_ASSERT_EQUAL(ESP_OK, ret);
}
TEST_CASE("bootloader_flash_xmc_startup can be called when cache disabled", "[spi_flash]")
{
test_xmc_startup();
}

View File

@ -394,6 +394,8 @@ done:
void test_spiffs_concurrent(const char* filename_prefix)
{
const int stack_size=3072;
char names[4][64];
for (size_t i = 0; i < 4; ++i) {
snprintf(names[i], sizeof(names[i]), "%s%d", filename_prefix, i + 1);
@ -406,8 +408,8 @@ void test_spiffs_concurrent(const char* filename_prefix)
printf("writing f1 and f2\n");
const int cpuid_0 = 0;
const int cpuid_1 = portNUM_PROCESSORS - 1;
xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, cpuid_0);
xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, cpuid_1);
xTaskCreatePinnedToCore(&read_write_task, "rw1", stack_size, &args1, 3, NULL, cpuid_0);
xTaskCreatePinnedToCore(&read_write_task, "rw2", stack_size, &args2, 3, NULL, cpuid_1);
xSemaphoreTake(args1.done, portMAX_DELAY);
printf("f1 done\n");
@ -423,10 +425,10 @@ void test_spiffs_concurrent(const char* filename_prefix)
printf("reading f1 and f2, writing f3 and f4\n");
xTaskCreatePinnedToCore(&read_write_task, "rw3", 2048, &args3, 3, NULL, cpuid_1);
xTaskCreatePinnedToCore(&read_write_task, "rw4", 2048, &args4, 3, NULL, cpuid_0);
xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, cpuid_0);
xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, cpuid_1);
xTaskCreatePinnedToCore(&read_write_task, "rw3", stack_size, &args3, 3, NULL, cpuid_1);
xTaskCreatePinnedToCore(&read_write_task, "rw4", stack_size, &args4, 3, NULL, cpuid_0);
xTaskCreatePinnedToCore(&read_write_task, "rw1", stack_size, &args1, 3, NULL, cpuid_0);
xTaskCreatePinnedToCore(&read_write_task, "rw2", stack_size, &args2, 3, NULL, cpuid_1);
xSemaphoreTake(args1.done, portMAX_DELAY);
printf("f1 done\n");