spi_flash: Add ESP32-C3 support

Based on internal commit 3ef01301fff
This commit is contained in:
Angus Gratton 2020-12-16 14:50:13 +11:00
parent c2364e133d
commit d4c9a45675
26 changed files with 493 additions and 98 deletions

View File

@ -78,6 +78,26 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
#if CONFIG_SPI_FLASH_ROM_IMPL
/*
* In S3 ROM, extra bits than 24-bit are used to indicate requirements of M7-M0:
* - 24: normal transactions
* - 28: 24bit DIO + conf bits (M7-M0 excluded from dummy_bitlen)
* - 32: 24bit QIO + conf bits (M7-M0 excluded from dummy_bitlen)
* Detect requirements for the conf bits by the address len, and modify the length to normal
* case (addr_bitlen = 24, dummy_bitlen includes M7-M0) as other chip versions use.
*/
int m70_bits = addr_bitlen - 24;
if (m70_bits) {
assert(io_mode == SPI_FLASH_DIO || io_mode == SPI_FLASH_QIO);
conf_required = true;
addr_bitlen -= m70_bits;
int line_width = (io_mode == SPI_FLASH_DIO? 2: 4);
dummy_cyclelen_base += m70_bits / line_width;
}
#endif //CONFIG_SPI_FLASH_ROM_IMPL
#if SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT #if SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT
// The CONTROL_DUMMY_OUTPUT feature is used to control M7-M0 bits. // The CONTROL_DUMMY_OUTPUT feature is used to control M7-M0 bits.
spi_flash_ll_set_dummy_out(dev, (conf_required? 1: 0), 1); spi_flash_ll_set_dummy_out(dev, (conf_required? 1: 0), 1);
@ -110,11 +130,18 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_tr
{ {
spi_dev_t *dev = get_spi_dev(host); spi_dev_t *dev = get_spi_dev(host);
esp_flash_io_mode_t io_mode = ((spi_flash_hal_context_t*)host)->base_io_mode; esp_flash_io_mode_t io_mode = ((spi_flash_hal_context_t*)host)->base_io_mode;
uint16_t command = trans->command; uint16_t command;
uint8_t dummy_bitlen = trans->dummy_bitlen; uint8_t dummy_bitlen;
if (trans->reserved != 0) {
// Back-compatible with caller functions of ESP32-S3 ROM
command = (uint8_t)trans->reserved;
dummy_bitlen = 0;
} else {
command = trans->command;
dummy_bitlen = trans->dummy_bitlen;
if ((trans->flags & SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO) != 0) { if ((trans->flags & SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO) != 0) {
io_mode = 0; io_mode = ((spi_flash_hal_context_t*)host)->base_io_mode;
}
} }
host->driver->configure_host_io_mode(host, command, trans->address_bitlen, dummy_bitlen, io_mode); host->driver->configure_host_io_mode(host, command, trans->address_bitlen, dummy_bitlen, io_mode);

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
#include "sdkconfig.h" #include "sdkconfig.h"
#ifndef CONFIG_SPI_FLASH_NEW_ROM_API #ifndef CONFIG_SPI_FLASH_ROM_IMPL
// HAL for // HAL for
// - MEMSPI // - MEMSPI
@ -95,4 +95,4 @@ bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host)
return idle; return idle;
} }
#endif // !CONFIG_SPI_FLASH_NEW_ROM_API #endif // !CONFIG_SPI_FLASH_ROM_IMPL

View File

@ -62,18 +62,7 @@ if(${spi_flash_mock})
else() else()
if(BOOTLOADER_BUILD) if(BOOTLOADER_BUILD)
if(CONFIG_IDF_TARGET_ESP32) set(srcs "${target}/spi_flash_rom_patch.c")
# ESP32 Bootloader needs SPIUnlock from this file, but doesn't
# need other parts of this component
set(srcs "esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
set(srcs "esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
set(srcs "esp32s3/spi_flash_rom_patch.c")
else()
# but on other platforms no source files are needed for bootloader
set(srcs)
endif()
set(cache_srcs "") set(cache_srcs "")
set(priv_requires bootloader_support soc) set(priv_requires bootloader_support soc)
else() else()
@ -81,21 +70,12 @@ else()
"cache_utils.c" "cache_utils.c"
"flash_mmap.c" "flash_mmap.c"
"flash_ops.c" "flash_ops.c"
"${IDF_TARGET}/flash_ops_${IDF_TARGET}.c" "${target}/flash_ops_${target}.c"
) )
set(srcs set(srcs
"partition.c") "partition.c"
"${target}/spi_flash_rom_patch.c"
if(CONFIG_IDF_TARGET_ESP32) )
list(APPEND srcs
"esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
list(APPEND srcs
"esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
list(APPEND srcs
"esp32s3/spi_flash_rom_patch.c")
endif()
# New implementation after IDF v4.0 # New implementation after IDF v4.0
list(APPEND srcs list(APPEND srcs

View File

@ -53,6 +53,19 @@ menu "SPI Flash driver"
to flash on ESP32-D2WD; (2) main SPI flash is connected to non-default pins; (3) main to flash on ESP32-D2WD; (2) main SPI flash is connected to non-default pins; (3) main
SPI flash chip is manufactured by ISSI. SPI flash chip is manufactured by ISSI.
config SPI_FLASH_ROM_IMPL
bool "Use esp_flash implementation in ROM"
depends on IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
default n
help
Enable this flag to use new SPI flash driver functions from ROM instead of ESP-IDF.
If keeping this as "n" in your project, you will have less free IRAM.
But you can use all of our flash features.
If making this as "y" in your project, you will increase free IRAM.
But you may miss out on some flash features and support for new flash chips.
choice SPI_FLASH_DANGEROUS_WRITE choice SPI_FLASH_DANGEROUS_WRITE
bool "Writing to dangerous flash regions" bool "Writing to dangerous flash regions"
default SPI_FLASH_DANGEROUS_WRITE_ABORTS default SPI_FLASH_DANGEROUS_WRITE_ABORTS

View File

@ -875,6 +875,50 @@ esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable, bool dcache_wrap_enable
} }
#endif #endif
#if CONFIG_IDF_TARGET_ESP32C3
static IRAM_ATTR void esp_enable_cache_flash_wrap(bool icache)
{
uint32_t i_autoload;
if (icache) {
i_autoload = Cache_Suspend_ICache();
}
REG_SET_BIT(EXTMEM_CACHE_WRAP_AROUND_CTRL_REG, EXTMEM_CACHE_FLASH_WRAP_AROUND);
if (icache) {
Cache_Resume_ICache(i_autoload);
}
}
esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable)
{
int flash_wrap_size = 0;
bool flash_support_wrap = false;
if (icache_wrap_enable) {
flash_wrap_size = 32;
}
#ifdef CONFIG_FLASHMODE_QIO
flash_support_wrap = true;
extern bool spi_flash_support_wrap_size(uint32_t wrap_size);
if (!spi_flash_support_wrap_size(flash_wrap_size)) {
flash_support_wrap = false;
ESP_EARLY_LOGW(TAG, "Flash do not support wrap size %d.", flash_wrap_size);
}
#else
ESP_EARLY_LOGW(TAG, "Flash is not in QIO mode, do not support wrap.");
#endif // CONFIG_FLASHMODE_QIO
extern esp_err_t spi_flash_enable_wrap(uint32_t wrap_size);
if (flash_support_wrap && flash_wrap_size > 0) {
ESP_EARLY_LOGI(TAG, "Flash wrap enabled, size = %d.", flash_wrap_size);
spi_flash_enable_wrap(flash_wrap_size);
esp_enable_cache_flash_wrap((flash_wrap_size > 0));
}
return ESP_OK;
}
#endif // CONFIG_IDF_TARGET_ESP32C3
void IRAM_ATTR spi_flash_enable_cache(uint32_t cpuid) void IRAM_ATTR spi_flash_enable_cache(uint32_t cpuid)
{ {
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32

View File

@ -0,0 +1,145 @@
// 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.
#include <string.h>
#include <sys/param.h>
#include "esp_spi_flash.h"
#include "soc/system_reg.h"
#include "soc/soc_memory_layout.h"
#include "esp32c3/rom/spi_flash.h"
#include "esp32c3/rom/cache.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash.h"
#include "esp_log.h"
static const char *TAG = "spiflash_c3";
#define SPICACHE SPIMEM0
#define SPIFLASH SPIMEM1
esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size)
{
const spi_flash_guard_funcs_t *ops = spi_flash_guard_get();
esp_rom_spiflash_result_t rc;
assert((dest_addr % 16) == 0);
assert((size % 16) == 0);
if (!esp_ptr_internal(src)) {
uint8_t block[128]; // Need to buffer in RAM as we write
while (size > 0) {
size_t next_block = MIN(size, sizeof(block));
memcpy(block, src, next_block);
esp_rom_spiflash_result_t r = spi_flash_write_encrypted_chip(dest_addr, block, next_block);
if (r != ESP_ROM_SPIFLASH_RESULT_OK) {
return r;
}
size -= next_block;
dest_addr += next_block;
src = ((uint8_t *)src) + next_block;
}
bzero(block, sizeof(block));
return ESP_ROM_SPIFLASH_RESULT_OK;
} else { // Already in internal memory
ESP_LOGV(TAG, "calling esp_rom_spiflash_write_encrypted addr 0x%x src %p size 0x%x", dest_addr, src, size);
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
/* The ROM function SPI_Encrypt_Write assumes ADDR_BITLEN is already set but new
implementation doesn't automatically set this to a usable value */
SPIFLASH.user1.usr_addr_bitlen = 23;
#endif
if (ops && ops->start) {
ops->start();
}
rc = esp_rom_spiflash_write_encrypted(dest_addr, (uint32_t *)src, size);
if (ops && ops->end) {
ops->end();
}
return rc;
}
}
#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;
}
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);
case 16:
return spi_flash_wrap_set(FLASH_WRAP_MODE_16B);
case 32:
return spi_flash_wrap_set(FLASH_WRAP_MODE_32B);
case 64:
return spi_flash_wrap_set(FLASH_WRAP_MODE_64B);
default:
return ESP_FAIL;
}
}
void spi_flash_disable_wrap(void)
{
spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
}
bool spi_flash_support_wrap_size(uint32_t wrap_size)
{
if (!REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FREAD_QIO) || !REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FASTRD_MODE)) {
return ESP_FAIL;
}
switch (wrap_size) {
case 0:
case 8:
case 16:
case 32:
case 64:
return true;
default:
return false;
}
}

View File

@ -0,0 +1,26 @@
// Copyright 2015-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.
#include "sdkconfig.h"
#include "esp32c3/rom/spi_flash.h"
#include "soc/spi_periph.h"
#include "spi_flash_defs.h"
#define SPI_IDX 1
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void)
{
REG_WRITE(SPI_MEM_CMD_REG(SPI_IDX), SPI_MEM_FLASH_WRDI);
while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0);
return ESP_ROM_SPIFLASH_RESULT_OK;
}

View File

@ -23,8 +23,6 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_flash_internal.h" #include "esp_flash_internal.h"
#include "spi_flash_chip_generic.h" //for spi_flash_chip_generic_yield()
static const char TAG[] = "spi_flash"; static const char TAG[] = "spi_flash";
#ifdef CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE #ifdef CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE
@ -70,10 +68,12 @@ _Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the i
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id); esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
static esp_err_t spiflash_start_default(esp_flash_t *chip); static esp_err_t spiflash_start_default(esp_flash_t *chip);
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err); static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip); static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length); static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
#endif //CONFIG_SPI_FLASH_ROM_IMPL
typedef struct { typedef struct {
esp_err_t (*start)(esp_flash_t *chip); esp_err_t (*start)(esp_flash_t *chip);
@ -82,6 +82,7 @@ typedef struct {
esp_err_t (*flash_end_flush_cache)(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length); esp_err_t (*flash_end_flush_cache)(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
} rom_spiflash_api_func_t; } rom_spiflash_api_func_t;
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
// These functions can be placed in the ROM. For now we use the code in IDF. // These functions can be placed in the ROM. For now we use the code in IDF.
DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = { DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
.start = spiflash_start_default, .start = spiflash_start_default,
@ -91,12 +92,17 @@ DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
}; };
DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api; DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api;
#else
extern rom_spiflash_api_func_t *esp_flash_api_funcs;
#define rom_spiflash_api_funcs esp_flash_api_funcs
#endif // CONFIG_SPI_FLASH_ROM_IMPL
/* Static function to notify OS of a new SPI flash operation. /* Static function to notify OS of a new SPI flash operation.
If returns an error result, caller must abort. If returns ESP_OK, caller must If returns an error result, caller must abort. If returns ESP_OK, caller must
call rom_spiflash_api_funcs->end() before returning. call rom_spiflash_api_funcs->end() before returning.
*/ */
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip) static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip)
{ {
if (chip->os_func != NULL && chip->os_func->start != NULL) { if (chip->os_func != NULL && chip->os_func->start != NULL) {
@ -155,10 +161,7 @@ static IRAM_ATTR esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t er
} }
return rom_spiflash_api_funcs->end(chip, err); return rom_spiflash_api_funcs->end(chip, err);
} }
#endif //CONFIG_SPI_FLASH_ROM_IMPL
/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);
/* Top-level API functions, calling into chip_drv functions via chip->drv */ /* Top-level API functions, calling into chip_drv functions via chip->drv */
@ -270,6 +273,7 @@ esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* out_id)
return read_id_core(chip, out_id, true); return read_id_core(chip, out_id, true);
} }
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t esp_flash_read_id(esp_flash_t* chip, uint32_t* out_id) esp_err_t esp_flash_read_id(esp_flash_t* chip, uint32_t* out_id)
{ {
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip); esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
@ -279,6 +283,7 @@ esp_err_t esp_flash_read_id(esp_flash_t* chip, uint32_t* out_id)
return read_id_core(chip, out_id, false); return read_id_core(chip, out_id, false);
} }
#endif //CONFIG_SPI_FLASH_ROM_IMPL
static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip) static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
{ {
@ -316,6 +321,8 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
return ESP_OK; return ESP_OK;
} }
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
/* Convenience macro for beginning of all API functions. /* Convenience macro for beginning of all API functions.
* Check the return value of `rom_spiflash_api_funcs->chip_check` is correct, * Check the return value of `rom_spiflash_api_funcs->chip_check` is correct,
* and the chip supports the operation in question. * and the chip supports the operation in question.
@ -327,6 +334,9 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
} \ } \
} while (0) } while (0)
/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);
esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size) esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{ {
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip); esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
@ -358,10 +368,12 @@ esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
CHECK_WRITE_ADDRESS(chip, 0, chip->size); CHECK_WRITE_ADDRESS(chip, 0, chip->size);
//check before the operation, in case this is called too close to the last operation //check before the operation, in case this is called too close to the last operation
err = spi_flash_chip_generic_yield(chip, false); if (chip->chip_drv->yield) {
err = chip->chip_drv->yield(chip, 0);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
}
err = rom_spiflash_api_funcs->start(chip); err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) { if (err != ESP_OK) {
@ -432,9 +444,11 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
bool bus_acquired = false; bool bus_acquired = false;
while (1) { while (1) {
//check before the operation, in case this is called too close to the last operation //check before the operation, in case this is called too close to the last operation
err = spi_flash_chip_generic_yield(chip, false); if (chip->chip_drv->yield) {
err = chip->chip_drv->yield(chip, 0);
if (err != ESP_OK) { if (err != ESP_OK) {
break; return err;
}
} }
err = rom_spiflash_api_funcs->start(chip); err = rom_spiflash_api_funcs->start(chip);
@ -707,9 +721,11 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
} }
//check before the operation, in case this is called too close to the last operation //check before the operation, in case this is called too close to the last operation
err = spi_flash_chip_generic_yield(chip, false); if (chip->chip_drv->yield) {
err = chip->chip_drv->yield(chip, 0);
if (err != ESP_OK) { if (err != ESP_OK) {
break; return err;
}
} }
err = rom_spiflash_api_funcs->start(chip); err = rom_spiflash_api_funcs->start(chip);
@ -814,6 +830,7 @@ IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
err = chip->chip_drv->set_io_mode(chip); err = chip->chip_drv->set_io_mode(chip);
return rom_spiflash_api_funcs->end(chip, err); return rom_spiflash_api_funcs->end(chip, err);
} }
#endif //CONFIG_SPI_FLASH_ROM_IMPL
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL #ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
esp_err_t esp_flash_app_disable_protect(bool disable) esp_err_t esp_flash_app_disable_protect(bool disable)

View File

@ -87,12 +87,18 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
.iomux = true, \ .iomux = true, \
.input_delay_ns = 0,\ .input_delay_ns = 0,\
} }
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/efuse.h"
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI_HOST,\
.speed = DEFAULT_FLASH_SPEED, \
.cs_num = 0, \
.iomux = true, \
.input_delay_ns = 0,\
}
#endif #endif
esp_flash_t *esp_flash_default_chip = NULL;
static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux, int cs_id) static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux, int cs_id)
{ {
//Not using spicommon_cs_initialize since we don't want to put the whole //Not using spicommon_cs_initialize since we don't want to put the whole
@ -111,11 +117,15 @@ static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_f
if (use_iomux) { if (use_iomux) {
PIN_FUNC_SELECT(iomux_reg, spics_func); PIN_FUNC_SELECT(iomux_reg, spics_func);
} else { } else {
#if CONFIG_IDF_TARGET_ESP32C3
GPIO.enable_w1ts.val = (0x1 << cs_io_num);
#else
if (cs_io_num < 32) { if (cs_io_num < 32) {
GPIO.enable_w1ts = (0x1 << cs_io_num); GPIO.enable_w1ts = (0x1 << cs_io_num);
} else { } else {
GPIO.enable1_w1ts.data = (0x1 << (cs_io_num - 32)); GPIO.enable1_w1ts.data = (0x1 << (cs_io_num - 32));
} }
#endif
GPIO.pin[cs_io_num].pad_driver = 0; GPIO.pin[cs_io_num].pad_driver = 0;
esp_rom_gpio_connect_out_signal(cs_io_num, spics_out, false, false); esp_rom_gpio_connect_out_signal(cs_io_num, spics_out, false, false);
if (cs_id == 0) { if (cs_id == 0) {
@ -208,10 +218,14 @@ esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip)
return ESP_OK; return ESP_OK;
} }
/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */ /* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */
extern const esp_flash_os_functions_t esp_flash_noos_functions; extern const esp_flash_os_functions_t esp_flash_noos_functions;
/* This pointer is defined in ROM and extern-ed on targets where CONFIG_SPI_FLASH_ROM_IMPL = y*/
#if !CONFIG_SPI_FLASH_ROM_IMPL
esp_flash_t *esp_flash_default_chip = NULL;
#endif
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL #ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
static DRAM_ATTR memspi_host_inst_t esp_flash_default_host; static DRAM_ATTR memspi_host_inst_t esp_flash_default_host;
@ -224,6 +238,7 @@ static DRAM_ATTR esp_flash_t default_chip = {
esp_err_t esp_flash_init_default_chip(void) esp_err_t esp_flash_init_default_chip(void)
{ {
const esp_rom_spiflash_chip_t *legacy_chip = &g_rom_flashchip;
memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT(); memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT();
#if !CONFIG_IDF_TARGET_ESP32 #if !CONFIG_IDF_TARGET_ESP32
@ -243,14 +258,15 @@ esp_err_t esp_flash_init_default_chip(void)
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
if (default_chip.size < g_rom_flashchip.chip_size) { if (default_chip.size < legacy_chip->chip_size) {
ESP_EARLY_LOGE(TAG, "Detected size(%dk) smaller than the size in the binary image header(%dk). Probe failed.", default_chip.size/1024, g_rom_flashchip.chip_size/1024); ESP_EARLY_LOGE(TAG, "Detected size(%dk) smaller than the size in the binary image header(%dk). Probe failed.", default_chip.size/1024, legacy_chip->chip_size/1024);
return ESP_ERR_FLASH_SIZE_NOT_MATCH; return ESP_ERR_FLASH_SIZE_NOT_MATCH;
} else if (default_chip.size > g_rom_flashchip.chip_size) { } else if (default_chip.size > legacy_chip->chip_size) {
ESP_EARLY_LOGW(TAG, "Detected size(%dk) larger than the size in the binary image header(%dk). Using the size in the binary image header.", default_chip.size/1024, g_rom_flashchip.chip_size/1024); ESP_EARLY_LOGW(TAG, "Detected size(%dk) larger than the size in the binary image header(%dk). Using the size in the binary image header.", default_chip.size/1024, legacy_chip->chip_size/1024);
default_chip.size = g_rom_flashchip.chip_size; default_chip.size = legacy_chip->chip_size;
} else {
default_chip.size = legacy_chip->chip_size;
} }
default_chip.size = g_rom_flashchip.chip_size;
esp_flash_default_chip = &default_chip; esp_flash_default_chip = &default_chip;
return ESP_OK; return ESP_OK;

View File

@ -107,6 +107,8 @@
#define PAGES_LIMIT (IROM0_PAGES_END > DROM0_PAGES_END ? IROM0_PAGES_END:DROM0_PAGES_END) #define PAGES_LIMIT (IROM0_PAGES_END > DROM0_PAGES_END ? IROM0_PAGES_END:DROM0_PAGES_END)
#define VADDR1_FIRST_USABLE_ADDR SOC_IROM_LOW #define VADDR1_FIRST_USABLE_ADDR SOC_IROM_LOW
#if !CONFIG_SPI_FLASH_ROM_IMPL
typedef struct mmap_entry_{ typedef struct mmap_entry_{
uint32_t handle; uint32_t handle;
int page; int page;
@ -405,12 +407,16 @@ uint32_t IRAM_ATTR spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory)
return count; return count;
} }
uint32_t spi_flash_cache2phys(const void *cached) size_t spi_flash_cache2phys(const void *cached)
{ {
intptr_t c = (intptr_t)cached; intptr_t c = (intptr_t)cached;
size_t cache_page; size_t cache_page;
int offset = 0; int offset = 0;
#if !CONFIG_IDF_TARGET_ESP32C3
if (c >= VADDR1_START_ADDR && c < VADDR1_FIRST_USABLE_ADDR) { if (c >= VADDR1_START_ADDR && c < VADDR1_FIRST_USABLE_ADDR) {
#else
if (c >= SOC_IRAM_LOW && c < VADDR1_FIRST_USABLE_ADDR) {
#endif
/* IRAM address, doesn't map to flash */ /* IRAM address, doesn't map to flash */
return SPI_FLASH_CACHE2PHYS_FAIL; return SPI_FLASH_CACHE2PHYS_FAIL;
} else if (c < VADDR1_FIRST_USABLE_ADDR) { } else if (c < VADDR1_FIRST_USABLE_ADDR) {
@ -564,3 +570,4 @@ IRAM_ATTR bool spi_flash_check_and_flush_cache(size_t start_addr, size_t length)
} }
return ret; return ret;
} }
#endif //!CONFIG_SPI_FLASH_ROM_IMPL

View File

@ -116,8 +116,6 @@ const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_no_os_ops = {
.yield = NULL, .yield = NULL,
}; };
static const spi_flash_guard_funcs_t *s_flash_guard_ops;
#ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS #ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
#define UNSAFE_WRITE_ADDRESS abort() #define UNSAFE_WRITE_ADDRESS abort()
#else #else
@ -132,7 +130,7 @@ static const spi_flash_guard_funcs_t *s_flash_guard_ops;
#define CHECK_WRITE_ADDRESS(ADDR, SIZE) #define CHECK_WRITE_ADDRESS(ADDR, SIZE)
#else /* FAILS or ABORTS */ #else /* FAILS or ABORTS */
#define CHECK_WRITE_ADDRESS(ADDR, SIZE) do { \ #define CHECK_WRITE_ADDRESS(ADDR, SIZE) do { \
if (s_flash_guard_ops && s_flash_guard_ops->is_safe_write_address && !s_flash_guard_ops->is_safe_write_address(ADDR, SIZE)) { \ if (guard && guard->is_safe_write_address && !guard->is_safe_write_address(ADDR, SIZE)) { \
return ESP_ERR_INVALID_ARG; \ return ESP_ERR_INVALID_ARG; \
} \ } \
} while(0) } while(0)
@ -146,14 +144,39 @@ static __attribute__((unused)) bool is_safe_write_address(size_t addr, size_t si
return true; return true;
} }
#if CONFIG_SPI_FLASH_ROM_IMPL
#include "esp_heap_caps.h"
typedef void *(*malloc_internal_cb_t)(size_t size);
void IRAM_ATTR *spi_flash_malloc_internal(size_t size)
{
return heap_caps_malloc(size, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
}
#endif
void spi_flash_init(void) void spi_flash_init(void)
{ {
spi_flash_init_lock(); spi_flash_init_lock();
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
spi_flash_reset_counters(); spi_flash_reset_counters();
#endif #endif
#if CONFIG_SPI_FLASH_ROM_IMPL
spi_flash_guard_set(&g_flash_guard_default_ops);
/* These two functions are in ROM only */
extern void spi_flash_mmap_os_func_set(void *(*func1)(size_t size), void (*func2)(void *p));
spi_flash_mmap_os_func_set(spi_flash_malloc_internal, heap_caps_free);
extern esp_err_t spi_flash_mmap_page_num_init(uint32_t page_num);
spi_flash_mmap_page_num_init(128);
#endif
} }
#if !CONFIG_SPI_FLASH_ROM_IMPL
static const spi_flash_guard_funcs_t *s_flash_guard_ops;
void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t *funcs) void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t *funcs)
{ {
s_flash_guard_ops = funcs; s_flash_guard_ops = funcs;
@ -164,6 +187,8 @@ const spi_flash_guard_funcs_t *IRAM_ATTR spi_flash_guard_get(void)
return s_flash_guard_ops; return s_flash_guard_ops;
} }
#endif
size_t IRAM_ATTR spi_flash_get_chip_size(void) size_t IRAM_ATTR spi_flash_get_chip_size(void)
{ {
return g_rom_flashchip.chip_size; return g_rom_flashchip.chip_size;
@ -171,29 +196,33 @@ size_t IRAM_ATTR spi_flash_get_chip_size(void)
static inline void IRAM_ATTR spi_flash_guard_start(void) static inline void IRAM_ATTR spi_flash_guard_start(void)
{ {
if (s_flash_guard_ops && s_flash_guard_ops->start) { const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
s_flash_guard_ops->start(); if (guard && guard->start) {
guard->start();
} }
} }
static inline void IRAM_ATTR spi_flash_guard_end(void) static inline void IRAM_ATTR spi_flash_guard_end(void)
{ {
if (s_flash_guard_ops && s_flash_guard_ops->end) { const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
s_flash_guard_ops->end(); if (guard && guard->end) {
guard->end();
} }
} }
static inline void IRAM_ATTR spi_flash_guard_op_lock(void) static inline void IRAM_ATTR spi_flash_guard_op_lock(void)
{ {
if (s_flash_guard_ops && s_flash_guard_ops->op_lock) { const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
s_flash_guard_ops->op_lock(); if (guard && guard->op_lock) {
guard->op_lock();
} }
} }
static inline void IRAM_ATTR spi_flash_guard_op_unlock(void) static inline void IRAM_ATTR spi_flash_guard_op_unlock(void)
{ {
if (s_flash_guard_ops && s_flash_guard_ops->op_unlock) { const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
s_flash_guard_ops->op_unlock(); if (guard && guard->op_unlock) {
guard->op_unlock();
} }
} }
@ -232,6 +261,7 @@ static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(void)
esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec)
{ {
const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
CHECK_WRITE_ADDRESS(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE); CHECK_WRITE_ADDRESS(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE); return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
} }
@ -240,6 +270,7 @@ esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec)
//deprecated, only used in compatible mode //deprecated, only used in compatible mode
esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size) esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size)
{ {
const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
CHECK_WRITE_ADDRESS(start_addr, size); CHECK_WRITE_ADDRESS(start_addr, size);
if (start_addr % SPI_FLASH_SEC_SIZE != 0) { if (start_addr % SPI_FLASH_SEC_SIZE != 0) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
@ -379,6 +410,7 @@ static IRAM_ATTR esp_rom_spiflash_result_t spi_flash_write_inner(uint32_t target
esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
{ {
const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
CHECK_WRITE_ADDRESS(dst, size); CHECK_WRITE_ADDRESS(dst, size);
// Out of bound writes are checked in ROM code, but we can give better // Out of bound writes are checked in ROM code, but we can give better
// error code here // error code here
@ -479,6 +511,7 @@ out:
esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size) esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
const spi_flash_guard_funcs_t *guard = spi_flash_guard_get();
CHECK_WRITE_ADDRESS(dest_addr, size); CHECK_WRITE_ADDRESS(dest_addr, size);
if ((dest_addr % 16) != 0) { if ((dest_addr % 16) != 0) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;

View File

@ -182,6 +182,10 @@ struct spi_flash_chip_t {
* Read the requested register (status, etc.). * Read the requested register (status, etc.).
*/ */
esp_err_t (*read_reg)(esp_flash_t *chip, spi_flash_register_t reg_id, uint32_t* out_reg); esp_err_t (*read_reg)(esp_flash_t *chip, spi_flash_register_t reg_id, uint32_t* out_reg);
/** Yield to other tasks. Called during erase operations. */
esp_err_t (*yield)(esp_flash_t *chip, uint32_t wip);
}; };
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used /* Pointer to an array of pointers to all known drivers for flash chips. This array is used

View File

@ -29,4 +29,8 @@
* chips, and GD25LQ chips, WRSR (01H) command is used; while WRSR2 (31H) is used for GD25Q32 - * chips, and GD25LQ chips, WRSR (01H) command is used; while WRSR2 (31H) is used for GD25Q32 -
* GD25Q127 chips. * GD25Q127 chips.
*/ */
esp_err_t spi_flash_chip_gd_probe(esp_flash_t *chip, uint32_t flash_id);
esp_err_t spi_flash_chip_gd_set_io_mode(esp_flash_t *chip);
esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
extern const spi_flash_chip_t esp_flash_chip_gd; extern const spi_flash_chip_t esp_flash_chip_gd;

View File

@ -392,7 +392,7 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool add
* @param wip Write (erase) in progress, `true` if this function is called during waiting idle of a erase/write command; else `false`. * @param wip Write (erase) in progress, `true` if this function is called during waiting idle of a erase/write command; else `false`.
* @return ESP_OK if success, otherwise failed. * @return ESP_OK if success, otherwise failed.
*/ */
esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, bool wip); esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, uint32_t wip);
/// Default timeout configuration used by most chips /// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout; const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@ -24,4 +24,8 @@
* default autodetection, this is used as a catchall if a more specific chip_drv * default autodetection, this is used as a catchall if a more specific chip_drv
* is not found. * is not found.
*/ */
esp_err_t spi_flash_chip_issi_probe(esp_flash_t *chip, uint32_t flash_id);
esp_err_t spi_flash_chip_issi_set_io_mode(esp_flash_t *chip);
esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
extern const spi_flash_chip_t esp_flash_chip_issi; extern const spi_flash_chip_t esp_flash_chip_issi;

View File

@ -22,7 +22,6 @@
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64 #define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
#define SPI_FLASH_HAL_MAX_READ_BYTES 64 #define SPI_FLASH_HAL_MAX_READ_BYTES 64
static const char TAG[] = "memspi";
DRAM_ATTR static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER(); DRAM_ATTR static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
@ -73,12 +72,20 @@ esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_
else { else {
host->inst.driver = &esp_flash_gpspi_host; host->inst.driver = &esp_flash_gpspi_host;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
if (cfg->host_id == SPI_HOST) {
host->inst.driver = &esp_flash_default_host;
}
#endif #endif
esp_err_t err = spi_flash_hal_init(host, cfg); esp_err_t err = spi_flash_hal_init(host, cfg);
return err; return err;
} }
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
static const char TAG[] = "memspi";
esp_err_t memspi_host_read_id_hs(spi_flash_host_inst_t *host, uint32_t *id) esp_err_t memspi_host_read_id_hs(spi_flash_host_inst_t *host, uint32_t *id)
{ {
uint32_t id_buf = 0; uint32_t id_buf = 0;
@ -214,3 +221,5 @@ int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address,
*align_address = address; *align_address = address;
return MIN(max_len, len); return MIN(max_len, len);
} }
#endif // CONFIG_SPI_FLASH_ROM_IMPL

View File

@ -14,8 +14,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "spi_flash_chip_generic.h" #include "spi_flash_chip_generic.h"
#include "spi_flash_chip_gd.h"
#include "spi_flash_defs.h" #include "spi_flash_defs.h"
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
#define FLASH_ID_MASK 0xFF00 #define FLASH_ID_MASK 0xFF00
#define FLASH_SIZE_MASK 0xFF #define FLASH_SIZE_MASK 0xFF
#define GD25Q_PRODUCT_ID 0x4000 #define GD25Q_PRODUCT_ID 0x4000
@ -70,7 +73,7 @@ esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t*
} }
return ret; return ret;
} }
#endif //CONFIG_SPI_FLASH_ROM_IMPL
static const char chip_name[] = "gd"; static const char chip_name[] = "gd";
@ -107,4 +110,5 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.get_io_mode = spi_flash_chip_gd_get_io_mode, .get_io_mode = spi_flash_chip_gd_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg, .read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
}; };

View File

@ -20,10 +20,6 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_attr.h" #include "esp_attr.h"
static const char TAG[] = "chip_generic";
typedef struct flash_chip_dummy { typedef struct flash_chip_dummy {
uint8_t dio_dummy_bitlen; uint8_t dio_dummy_bitlen;
uint8_t qio_dummy_bitlen; uint8_t qio_dummy_bitlen;
@ -62,6 +58,10 @@ const DRAM_ATTR flash_chip_op_timeout_t spi_flash_chip_generic_timeout = {
.page_program_timeout = SPI_FLASH_GENERIC_PAGE_PROGRAM_TIMEOUT_MS * 1000, .page_program_timeout = SPI_FLASH_GENERIC_PAGE_PROGRAM_TIMEOUT_MS * 1000,
}; };
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
static const char TAG[] = "chip_generic";
esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id) esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id)
{ {
// This is the catch-all probe function, claim the chip always if nothing // This is the catch-all probe function, claim the chip always if nothing
@ -322,7 +322,7 @@ esp_err_t spi_flash_chip_generic_read_reg(esp_flash_t* chip, spi_flash_register_
return chip->host->driver->read_status(chip->host, (uint8_t*)out_reg); return chip->host->driver->read_status(chip->host, (uint8_t*)out_reg);
} }
esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, bool wip) esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, uint32_t wip)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
uint32_t flags = wip? 1: 0; //check_yield() and yield() impls should not issue suspend/resume if this flag is zero uint32_t flags = wip? 1: 0; //check_yield() and yield() impls should not issue suspend/resume if this flag is zero
@ -472,6 +472,7 @@ esp_err_t spi_flash_chip_generic_set_io_mode(esp_flash_t *chip)
spi_flash_common_read_status_16b_rdsr_rdsr2, spi_flash_common_read_status_16b_rdsr_rdsr2,
BIT_QE); BIT_QE);
} }
#endif // CONFIG_SPI_FLASH_ROM_IMPL
static const char chip_name[] = "generic"; static const char chip_name[] = "generic";
@ -509,8 +510,10 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.get_io_mode = spi_flash_chip_generic_get_io_mode, .get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg, .read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
}; };
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
/******************************************************************************* /*******************************************************************************
* Utility functions * Utility functions
******************************************************************************/ ******************************************************************************/
@ -647,3 +650,5 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
} }
return ret; return ret;
} }
#endif // !CONFIG_SPI_FLASH_ROM_IMPL

View File

@ -14,6 +14,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "spi_flash_chip_generic.h" #include "spi_flash_chip_generic.h"
#include "spi_flash_chip_issi.h"
#include "spi_flash_defs.h" #include "spi_flash_defs.h"
/* Driver for ISSI flash chip, as used in ESP32 D2WD */ /* Driver for ISSI flash chip, as used in ESP32 D2WD */
@ -93,4 +94,5 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.get_io_mode = spi_flash_chip_issi_get_io_mode, .get_io_mode = spi_flash_chip_issi_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg, .read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
}; };

View File

@ -72,4 +72,5 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.get_io_mode = spi_flash_chip_mxic_get_io_mode, .get_io_mode = spi_flash_chip_mxic_get_io_mode,
.read_reg = spi_flash_chip_mxic_read_reg, .read_reg = spi_flash_chip_mxic_read_reg,
.yield = spi_flash_chip_generic_yield,
}; };

View File

@ -175,6 +175,7 @@ const spi_flash_chip_t esp_flash_chip_winbond = {
.get_io_mode = spi_flash_chip_generic_get_io_mode, .get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg, .read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
}; };

View File

@ -38,6 +38,12 @@ typedef struct {
uint32_t dcache_autoload; uint32_t dcache_autoload;
} spi_noos_arg_t; } spi_noos_arg_t;
static DRAM_ATTR spi_noos_arg_t spi_arg = { 0 };
#elif CONFIG_IDF_TARGET_ESP32C3
typedef struct {
uint32_t icache_autoload;
} spi_noos_arg_t;
static DRAM_ATTR spi_noos_arg_t spi_arg = { 0 }; static DRAM_ATTR spi_noos_arg_t spi_arg = { 0 };
#endif #endif
@ -50,6 +56,9 @@ static IRAM_ATTR esp_err_t start(void *arg)
spi_noos_arg_t *spi_arg = arg; spi_noos_arg_t *spi_arg = arg;
spi_arg->icache_autoload = Cache_Suspend_ICache(); spi_arg->icache_autoload = Cache_Suspend_ICache();
spi_arg->dcache_autoload = Cache_Suspend_DCache(); spi_arg->dcache_autoload = Cache_Suspend_DCache();
#elif CONFIG_IDF_TARGET_ESP32C3
spi_noos_arg_t *spi_arg = arg;
spi_arg->icache_autoload = Cache_Suspend_ICache();
#endif #endif
return ESP_OK; return ESP_OK;
} }
@ -80,6 +89,13 @@ static IRAM_ATTR esp_err_t delay_us(void *arg, uint32_t us)
return ESP_OK; return ESP_OK;
} }
// Currently when the os is not up yet, the caller is supposed to call esp_flash APIs with proper
// buffers.
IRAM_ATTR void* get_temp_buffer_not_supported(void* arg, size_t reqest_size, size_t* out_size)
{
return NULL;
}
const DRAM_ATTR esp_flash_os_functions_t esp_flash_noos_functions = { const DRAM_ATTR esp_flash_os_functions_t esp_flash_noos_functions = {
.start = start, .start = start,
.end = end, .end = end,

View File

@ -22,6 +22,7 @@
#include "ccomp_timer.h" #include "ccomp_timer.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "esp_timer.h"
#define FUNC_SPI 1 #define FUNC_SPI 1
@ -82,6 +83,26 @@ static uint8_t sector_buf[4096];
#define FSPI_PIN_NUM_WP 38 #define FSPI_PIN_NUM_WP 38
#define FSPI_PIN_NUM_CS 34 #define FSPI_PIN_NUM_CS 34
// Just use the same pins for HSPI
#define HSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI
#define HSPI_PIN_NUM_MISO FSPI_PIN_NUM_MISO
#define HSPI_PIN_NUM_CLK FSPI_PIN_NUM_CLK
#define HSPI_PIN_NUM_HD FSPI_PIN_NUM_HD
#define HSPI_PIN_NUM_WP FSPI_PIN_NUM_WP
#define HSPI_PIN_NUM_CS FSPI_PIN_NUM_CS
#elif CONFIG_IDF_TARGET_ESP32C3
#define SPI1_CS_IO 26 //the pin which is usually used by the PSRAM cs
#define SPI1_HD_IO 27 //the pin which is usually used by the PSRAM hd
#define SPI1_WP_IO 28 //the pin which is usually used by the PSRAM wp
#define FSPI_PIN_NUM_MOSI 7
#define FSPI_PIN_NUM_MISO 2
#define FSPI_PIN_NUM_CLK 6
#define FSPI_PIN_NUM_HD 4
#define FSPI_PIN_NUM_WP 5
#define FSPI_PIN_NUM_CS 10
// Just use the same pins for HSPI // Just use the same pins for HSPI
#define HSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI #define HSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI
#define HSPI_PIN_NUM_MISO FSPI_PIN_NUM_MISO #define HSPI_PIN_NUM_MISO FSPI_PIN_NUM_MISO
@ -108,7 +129,8 @@ typedef void (*flash_test_func_t)(const esp_partition_t *part);
These tests run for all the flash chip configs shown in config_list, below (internal and external). These tests run for all the flash chip configs shown in config_list, below (internal and external).
*/ */
#if defined(CONFIG_SPIRAM) #if defined(CONFIG_SPIRAM) || TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)
#define FLASH_TEST_CASE_3(STR, FUNCT_TO_RUN) #define FLASH_TEST_CASE_3(STR, FUNCT_TO_RUN)
#define FLASH_TEST_CASE_3_IGNORE(STR, FUNCT_TO_RUN) #define FLASH_TEST_CASE_3_IGNORE(STR, FUNCT_TO_RUN)
#else #else
@ -188,7 +210,20 @@ flashtest_config_t config_list[] = {
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
flashtest_config_t config_list[] = { flashtest_config_t config_list[] = {
FLASHTEST_CONFIG_COMMON, FLASHTEST_CONFIG_COMMON,
/* No runners for esp32s2 for these config yet */ /* No runners for esp32s3 for these config yet */
{
.io_mode = TEST_SPI_READ_MODE,
.speed = TEST_SPI_SPEED,
.host_id = FSPI_HOST,
.cs_id = 0,
.cs_io_num = FSPI_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
#elif CONFIG_IDF_TARGET_ESP32C3
flashtest_config_t config_list[] = {
FLASHTEST_CONFIG_COMMON,
/* No runners for esp32c3 for these config yet */
{ {
.io_mode = TEST_SPI_READ_MODE, .io_mode = TEST_SPI_READ_MODE,
.speed = TEST_SPI_SPEED, .speed = TEST_SPI_SPEED,
@ -197,16 +232,6 @@ flashtest_config_t config_list[] = {
.cs_io_num = FSPI_PIN_NUM_CS, .cs_io_num = FSPI_PIN_NUM_CS,
.input_delay_ns = 0, .input_delay_ns = 0,
}, },
// /* current runner doesn't have a flash on HSPI */
// {
// .io_mode = TEST_SPI_READ_MODE,
// .speed = TEST_SPI_SPEED,
// .host_id = HSPI_HOST,
// .cs_id = 0,
// // uses GPIO matrix on esp32s2 regardless if FORCE_GPIO_MATRIX
// .cs_io_num = HSPI_PIN_NUM_CS,
// .input_delay_ns = 20,
// },
}; };
#endif #endif
@ -296,7 +321,7 @@ static void setup_bus(spi_host_device_t host_id)
gpio_set_level(HSPI_PIN_NUM_WP, 1); gpio_set_level(HSPI_PIN_NUM_WP, 1);
#endif #endif
} }
#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) #if !DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3)
else if (host_id == VSPI_HOST) { else if (host_id == VSPI_HOST) {
ESP_LOGI(TAG, "setup flash on SPI%d (VSPI) CS0...\n", host_id + 1); ESP_LOGI(TAG, "setup flash on SPI%d (VSPI) CS0...\n", host_id + 1);
spi_bus_config_t vspi_bus_cfg = { spi_bus_config_t vspi_bus_cfg = {
@ -801,12 +826,14 @@ TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash
} }
#ifndef CONFIG_SPIRAM #ifndef CONFIG_SPIRAM
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)
TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash_3][test_env=UT_T1_ESP_FLASH]") TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash_3][test_env=UT_T1_ESP_FLASH]")
{ {
for (int i = 0; i < TEST_CONFIG_NUM; i++) { for (int i = 0; i < TEST_CONFIG_NUM; i++) {
test_permutations_chip(&config_list[i]); test_permutations_chip(&config_list[i]);
} }
} }
#endif //TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)
#endif #endif

View File

@ -153,6 +153,9 @@ TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]")
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
} }
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)
// TODO ESP32C3 IDF-2458
TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]") TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]")
{ {
setup_mmap_tests(); setup_mmap_tests();
@ -209,6 +212,9 @@ TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]")
} }
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)
TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash][mmap]") TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash][mmap]")
{ {
int nopages; int nopages;
@ -352,7 +358,8 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]")
{ {
uint8_t buf[64]; uint8_t buf[64];
static const uint8_t constant_data[] = { 1, 2, 3, 7, 11, 16, 3, 88 }; /* Avoid put constant data in the sdata/sdata2 section */
static const uint8_t constant_data[] = { 1, 2, 3, 7, 11, 16, 3, 88, 99};
/* esp_partition_find is in IROM */ /* esp_partition_find is in IROM */
uint32_t phys = spi_flash_cache2phys(esp_partition_find); uint32_t phys = spi_flash_cache2phys(esp_partition_find);

View File

@ -238,7 +238,7 @@ TEST_CASE("Test spi_flash_write", "[spi_flash][esp_flash]")
* NB: At the moment these only support aligned addresses, because memcpy * NB: At the moment these only support aligned addresses, because memcpy
* is not aware of the 32-but load requirements for these regions. * is not aware of the 32-but load requirements for these regions.
*/ */
#ifdef CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
#define TEST_SOC_IROM_ADDR (SOC_IROM_LOW) #define TEST_SOC_IROM_ADDR (SOC_IROM_LOW)
#define TEST_SOC_CACHE_RAM_BANK0_ADDR (SOC_IRAM_LOW) #define TEST_SOC_CACHE_RAM_BANK0_ADDR (SOC_IRAM_LOW)
#define TEST_SOC_CACHE_RAM_BANK1_ADDR (SOC_IRAM_LOW + 0x2000) #define TEST_SOC_CACHE_RAM_BANK1_ADDR (SOC_IRAM_LOW + 0x2000)

View File

@ -13,6 +13,7 @@
#include "ccomp_timer.h" #include "ccomp_timer.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "esp_timer.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@ -21,6 +22,8 @@
#include "esp32s2/rom/spi_flash.h" #include "esp32s2/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h"
#endif #endif
struct flash_test_ctx { struct flash_test_ctx {
@ -391,9 +394,9 @@ TEST_CASE("spi_flash deadlock with high priority busy-waiting task", "[spi_flash
TEST_CASE("WEL is cleared after boot", "[spi_flash]") TEST_CASE("WEL is cleared after boot", "[spi_flash]")
{ {
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; esp_rom_spiflash_chip_t *legacy_chip = &g_rom_flashchip;
uint32_t status; uint32_t status;
esp_rom_spiflash_read_status(&g_rom_spiflash_chip, &status); esp_rom_spiflash_read_status(legacy_chip, &status);
TEST_ASSERT((status & 0x2) == 0); TEST_ASSERT((status & 0x2) == 0);
} }
@ -402,15 +405,15 @@ TEST_CASE("WEL is cleared after boot", "[spi_flash]")
// ISSI chip has its QE bit on other chips' BP4, which may get cleared by accident // ISSI chip has its QE bit on other chips' BP4, which may get cleared by accident
TEST_CASE("rom unlock will not erase QE bit", "[spi_flash]") TEST_CASE("rom unlock will not erase QE bit", "[spi_flash]")
{ {
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; esp_rom_spiflash_chip_t *legacy_chip = &g_rom_flashchip;
uint32_t status; uint32_t status;
printf("dev_id: %08X \n", g_rom_spiflash_chip.device_id); printf("dev_id: %08X \n", legacy_chip->device_id);
if (((g_rom_spiflash_chip.device_id >> 16) & 0xff) != 0x9D) { if (((legacy_chip->device_id >> 16) & 0xff) != 0x9D) {
TEST_IGNORE_MESSAGE("This test is only for ISSI chips. Ignore."); TEST_IGNORE_MESSAGE("This test is only for ISSI chips. Ignore.");
} }
esp_rom_spiflash_unlock(); esp_rom_spiflash_unlock();
esp_rom_spiflash_read_status(&g_rom_spiflash_chip, &status); esp_rom_spiflash_read_status(legacy_chip, &status);
printf("status: %08x\n", status); printf("status: %08x\n", status);
TEST_ASSERT(status & 0x40); TEST_ASSERT(status & 0x40);