esp_flash: add opi flash support in esp_flash chip driver, for MXIC

This commit is contained in:
Cao Sen Miao 2021-09-01 15:58:15 +08:00
parent 559c1ac3f9
commit 6c0aebe279
33 changed files with 904 additions and 165 deletions

View File

@ -372,6 +372,9 @@ void IRAM_ATTR call_start_cpu0(void)
#endif // CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
esp_mspi_pin_init();
// For Octal flash, it's hard to implement a read_id function in OPI mode for all vendors.
// So we have to read it here in SPI mode, before entering the OPI mode.
bootloader_flash_update_id();
#if CONFIG_ESPTOOLPY_OCT_FLASH
bool efuse_opflash_en = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA3_REG, EFUSE_FLASH_TYPE);
if (!efuse_opflash_en) {
@ -571,7 +574,6 @@ void IRAM_ATTR call_start_cpu0(void)
}
#endif
bootloader_flash_update_id();
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
__attribute__((unused)) esp_image_header_t fhdr = {0};
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM

View File

@ -75,8 +75,33 @@ menu "Serial flasher config"
bool "MXIC OPI FLASH(MX25UM25645G)"
endchoice
choice ESPTOOLPY_FLASHMODE
prompt "Flash SPI mode"
default ESPTOOLPY_FLASHMODE_DIO
default ESPTOOLPY_FLASHMODE_OPI if ESPTOOLPY_OCT_FLASH
help
Mode the flash chip is flashed in, as well as the default mode for the
binary to run in.
config ESPTOOLPY_FLASHMODE_QIO
depends on !ESPTOOLPY_OCT_FLASH
bool "QIO"
config ESPTOOLPY_FLASHMODE_QOUT
depends on !ESPTOOLPY_OCT_FLASH
bool "QOUT"
config ESPTOOLPY_FLASHMODE_DIO
depends on !ESPTOOLPY_OCT_FLASH
bool "DIO"
config ESPTOOLPY_FLASHMODE_DOUT
depends on !ESPTOOLPY_OCT_FLASH
bool "DOUT"
config ESPTOOLPY_FLASHMODE_OPI
depends on ESPTOOLPY_OCT_FLASH
bool "OPI"
endchoice
choice ESPTOOLPY_FLASHMODE_OCT
depends on ESPTOOLPY_OCT_FLASH
depends on ESPTOOLPY_FLASHMODE_OPI
prompt "Flash OPI mode"
default ESPTOOLPY_FLASHMODE_OPI_DTR
@ -88,28 +113,6 @@ menu "Serial flasher config"
bool "OPI_DTR"
endchoice
choice ESPTOOLPY_FLASHMODE
prompt "Flash SPI mode"
default ESPTOOLPY_FLASHMODE_DIO
depends on !ESPTOOLPY_OCT_FLASH
help
Mode the flash chip is flashed in, as well as the default mode for the
binary to run in.
config ESPTOOLPY_FLASHMODE_QIO
bool "QIO"
config ESPTOOLPY_FLASHMODE_QOUT
bool "QOUT"
config ESPTOOLPY_FLASHMODE_DIO
bool "DIO"
config ESPTOOLPY_FLASHMODE_DOUT
bool "DOUT"
config ESPTOOLPY_FLASHMODE_FASTRD
bool "FASTRD"
config ESPTOOLPY_FLASHMODE_SLOWRD
bool "SLOWRD"
endchoice
# Note: we use esptool.py to flash bootloader in
# dio mode for QIO/QOUT, bootloader then upgrades
# itself to quad mode during initialisation
@ -119,10 +122,11 @@ menu "Serial flasher config"
default "dio" if ESPTOOLPY_FLASHMODE_QOUT
default "dio" if ESPTOOLPY_FLASHMODE_DIO
default "dout" if ESPTOOLPY_FLASHMODE_DOUT
default "dout" if ESPTOOLPY_FLASHMODE_FASTRD
default "dout" if ESPTOOLPY_FLASHMODE_SLOWRD
default "dout" if ESPTOOLPY_FLASHMODE_OPI_STR
default "dout" if ESPTOOLPY_FLASHMODE_OPI_DTR
# The 1st and 2nd bootloader doesn't support opi mode,
# using fastrd instead. For now the ESPTOOL doesn't support
# fasted (see ESPTOOL-274), using dout instead. In ROM the flash mode
# information get from efuse, so don't care this dout choice.
default "dout" if ESPTOOLPY_FLASHMODE_OPI
choice ESPTOOLPY_FLASHFREQ
prompt "Flash SPI speed"

View File

@ -382,7 +382,8 @@ static inline void spimem_flash_ll_set_cs_pin(spi_mem_dev_t *dev, int pin)
static inline void spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M);
ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M | SPI_MEM_FCMD_OCT | SPI_MEM_FADDR_OCT | SPI_MEM_FDIN_OCT | SPI_MEM_FDOUT_OCT);
dev->ddr.fmem_ddr_en = 0;
ctrl.val |= SPI_MEM_FASTRD_MODE_M;
switch (read_mode) {
case SPI_FLASH_FASTRD:
@ -403,6 +404,19 @@ static inline void spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_i
case SPI_FLASH_SLOWRD:
ctrl.fastrd_mode = 0;
break;
case SPI_FLASH_OPI_STR:
ctrl.faddr_oct = 1;
ctrl.fcmd_oct = 1;
ctrl.fdin_oct = 1;
ctrl.fdout_oct = 1;
break;
case SPI_FLASH_OPI_DTR:
ctrl.faddr_oct = 1;
ctrl.fcmd_oct = 1;
ctrl.fdin_oct = 1;
ctrl.fdout_oct = 1;
dev->ddr.fmem_ddr_en = 1;
break;
default:
abort();
}
@ -546,6 +560,11 @@ static inline void spimem_flash_ll_set_cs_setup(spi_mem_dev_t *dev, uint32_t cs_
dev->ctrl2.cs_setup_time = cs_setup_time - 1;
}
static inline void spimem_flash_ll_set_extra_dummy(spi_mem_dev_t *dev, uint32_t extra_dummy)
{
dev->timing_cali.extra_dummy_cyclelen = extra_dummy;
}
#ifdef __cplusplus
}
#endif

View File

@ -51,20 +51,41 @@ typedef struct {
uint32_t flags; ///< Flags for configurations with one set of driver code. (e.g. QPI mode, auto-suspend mode, 64-bit address mode, etc.)
#define SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND BIT(0) ///< When the auto-suspend is setup in configuration.
#define SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME BIT(1) ///< Setup auto-resume feature.
#define SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE BIT(2) ///< Flash works under octal spi mode.
spi_flash_sus_cmd_conf sus_cfg; ///< To store suspend command/mask information.
uint32_t slicer_flags; /// Slicer flags for configuring how to slice data correctly while reading or writing.
#define SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR BIT(0) ///< Slice data according to DTR mode, the address and length must be even (A0=0).
} spi_flash_hal_context_t;
_Static_assert(sizeof(spi_flash_hal_context_t) == 36, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
_Static_assert(sizeof(spi_flash_hal_context_t) == 40, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// This struct provide MSPI Flash necessary timing related config, should be consistent with that in union in `spi_flash_hal_config_t`.
typedef struct {
uint32_t extra_dummy;
uint32_t cs_hold;
uint8_t cs_setup;
spi_flash_ll_clock_reg_t clock_config;
} spi_flash_hal_timing_config_t;
/// Configuration structure for the SPI driver.
typedef struct {
spi_host_device_t host_id; ///< SPI peripheral ID.
int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1).
union {
struct {
uint32_t extra_dummy; ///< extra dummy for timing compensation.
uint32_t cs_hold; ///< CS hold time config used by the host
uint8_t cs_setup; ///< (cycles-1) of prepare phase by spi clock
spi_flash_ll_clock_reg_t clock_config; ///< (optional) Clock configuration for Octal flash.
};
spi_flash_hal_timing_config_t timing_reg; ///< Reconfigure timing tuning regs.
};
bool iomux; ///< Whether the IOMUX is used, used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock, used for timing compensation.
esp_flash_speed_t speed;///< SPI flash clock speed to work at.
uint32_t cs_hold; ///< CS hold time config used by the host
uint8_t cs_setup; ///< (cycles-1) of prepare phase by spi clock
spi_host_device_t host_id; ///< SPI peripheral ID.
int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1).
bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable.
bool octal_mode_en; ///< Octal spi flash mode enable bit 1: enable, 0: disable.
bool using_timing_tuning; ///< System exist SPI0/1 timing tuning, using value from system directely if set to 1.
esp_flash_io_mode_t default_io_mode; ///< Default flash io mode.
} spi_flash_hal_config_t;
/**

View File

@ -37,6 +37,7 @@ typedef struct {
#define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
uint16_t command; ///< Command to send
uint8_t dummy_bitlen; ///< Basic dummy bits to use
uint32_t io_mode; ///< Flash working mode when `SPI_FLASH_IGNORE_BASEIO` is specified.
} spi_flash_trans_t;
/**
@ -54,6 +55,7 @@ typedef enum {
ESP_FLASH_26MHZ, ///< The flash runs under 26MHz
ESP_FLASH_40MHZ, ///< The flash runs under 40MHz
ESP_FLASH_80MHZ, ///< The flash runs under 80MHz
ESP_FLASH_120MHZ, ///< The flash runs under 120MHz, 120MHZ can only be used by main flash after timing tuning in system. Do not use this directely in any API.
ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``.
} esp_flash_speed_t;
@ -71,7 +73,9 @@ typedef enum {
SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O
SPI_FLASH_QOUT, ///< Data read using quad I/O
SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O
#define SPI_FLASH_OPI_FLAG 16 ///< A flag for flash work in opi mode, the io mode below are opi, above are SPI/QSPI mode. DO NOT use this value in any API.
SPI_FLASH_OPI_STR = SPI_FLASH_OPI_FLAG,///< Only support on OPI flash, flash read and write under STR mode
SPI_FLASH_OPI_DTR,///< Only support on OPI flash, flash read and write under DTR mode
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
} esp_flash_io_mode_t;

View File

@ -71,6 +71,26 @@ static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk
return apb_period_n / apbclk_n;
}
#if SOC_SPI_MEM_SUPPORT_TIME_TUNING
static inline int extra_dummy_under_timing_tuning(const spi_flash_hal_config_t *cfg)
{
bool main_flash = (cfg->host_id == SPI1_HOST && cfg->cs_num == 0);
int extra_dummy = 0;
if (main_flash) {
/**
* For Octal Flash, the dummy is `usr_dummy` + `extra_dummy`, they are in two different regs, we don't touch `extra_dummy` here, so set extra_dummy 0.
* Instead, for both Quad and Octal Flash, we use `usr_dummy` and set the whole dummy length (usr_dummy + extra_dummy) to this register.
*/
extra_dummy = cfg->extra_dummy;
} else {
// TODO: for other flash chips, dummy get logic implement here. Currently, still calculate extra dummy by itself.
abort();
}
return extra_dummy;
}
#endif //SOC_SPI_MEM_SUPPORT_TIME_TUNING
esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_hal_config_t *cfg)
{
if (!esp_ptr_internal(data_out) && cfg->host_id == SPI1_HOST) {
@ -87,16 +107,37 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
.inst = data_out->inst, // Keeps the function pointer table
.spi = spi_flash_ll_get_hw(cfg->host_id),
.cs_num = cfg->cs_num,
.extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, APB_CLK_FREQ/clock_cfg->div),
.clock_conf = clock_cfg->clock_reg_val,
.cs_hold = cfg->cs_hold,
.cs_setup = cfg->cs_setup,
.base_io_mode = cfg->default_io_mode,
};
#if SOC_SPI_MEM_SUPPORT_TIME_TUNING
if (cfg->using_timing_tuning) {
data_out->extra_dummy = extra_dummy_under_timing_tuning(cfg);
data_out->clock_conf = cfg->clock_config;
} else
#endif // SOC_SPI_MEM_SUPPORT_TIME_TUNING
{
data_out->extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, APB_CLK_FREQ/clock_cfg->div);
data_out->clock_conf = clock_cfg->clock_reg_val;
}
if (cfg->auto_sus_en) {
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND;
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME;
}
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
if (cfg->octal_mode_en) {
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE;
}
if (cfg->default_io_mode == SPI_FLASH_OPI_DTR) {
data_out->slicer_flags |= SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR;
}
#endif
HAL_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy);
return ESP_OK;
}

View File

@ -65,6 +65,10 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host)
spi_flash_hal_disable_auto_resume_mode(host);
}
#endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#if SOC_SPI_MEM_SUPPORT_TIME_TUNING
// Always keep the extra dummy on SPI1 is 0, add extra dummy to user dummy
spimem_flash_ll_set_extra_dummy((spi_mem_dev_t*)dev, 0);
#endif
#else
gpspi_flash_ll_set_hold_pol(dev, 1);
#endif //GPSPI_BUILD
@ -139,7 +143,7 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_tr
command = trans->command;
dummy_bitlen = trans->dummy_bitlen;
if ((trans->flags & SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO) != 0) {
io_mode = ((spi_flash_hal_context_t*)host)->base_io_mode;
io_mode = trans->io_mode;
}
}

View File

@ -262,6 +262,9 @@
#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_RESUME (1)
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_OPI_MODE (1)
#define SOC_SPI_MEM_SUPPORT_TIME_TUNING (1)
/*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/
#define SOC_COEX_HW_PTI (1)

View File

@ -34,6 +34,7 @@ else()
"spi_flash_chip_gd.c"
"spi_flash_chip_winbond.c"
"spi_flash_chip_boya.c"
"spi_flash_chip_mxic_opi.c"
"memspi_host_driver.c")
list(APPEND cache_srcs

View File

@ -248,6 +248,15 @@ menu "SPI Flash driver"
given by ``chip_drv`` member of the chip struct. This adds support for variant
chips, however will extend detecting time.
config SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
bool "mxic (opi)"
depends on IDF_TARGET_ESP32S3
default y
help
Enable this to support auto detection of Octal MXIC chips if chip vendor not directly
given by ``chip_drv`` member of the chip struct. This adds support for variant
chips, however will extend detecting time.
endmenu #auto detect flash chips
config SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE

View File

@ -358,3 +358,58 @@ void spi_timing_config_psram_tune_dummy(uint8_t extra_dummy)
}
#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
static bool spi_timing_config_cs_setup_enable(void)
{
return REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_SETUP);
}
static bool spi_timing_config_cs_hold_enable(void)
{
return REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD);
}
bool spi_timine_config_flash_is_tuned(void)
{
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
return true;
#else
return false;
#endif
}
/**
* Get the SPI1 Flash CS timing setting. The setup time and hold time are both realistic cycles.
* @note On ESP32-S3, SPI0/1 share the Flash CS timing registers. Therefore, we should not change these values.
* @note This function inform `spi_flash_timing_tuning.c` (driver layer) of the cycle,
* and other component (esp_flash driver) should get these cycle and configure the registers accordingly.
*/
void spi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time)
{
*setup_time = REG_GET_FIELD(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME);
*hold_time = REG_GET_FIELD(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME);
/**
* The logic here is, if setup_en / hold_en is false, then we return the realistic cycle number,
* which is 0. If true, then the realistic cycle number is (reg_value + 1)
*/
if (spi_timing_config_cs_setup_enable()) {
*setup_time += 1;
} else {
*setup_time = 0;
}
if (spi_timing_config_cs_hold_enable()) {
*hold_time += 1;
} else {
*hold_time = 0;
}
}
/**
* Get the SPI1 Flash clock setting.
* @note Similarly, this function inform `spi_flash_timing_tuning.c` (driver layer) of the clock setting,
* and other component (esp_flash driver) should get these and configure the registers accordingly.
*/
uint32_t spi_timing_config_get_flash_clock_reg(void)
{
return READ_PERI_REG(SPI_MEM_CLOCK_REG(1));
}

View File

@ -242,6 +242,14 @@ void spi_timing_config_flash_tune_din_num_mode(uint8_t din_mode, uint8_t din_num
void spi_timing_config_flash_tune_dummy(uint8_t extra_dummy);
void spi_timing_config_psram_tune_din_num_mode(uint8_t din_mode, uint8_t din_num);
void spi_timing_config_psram_tune_dummy(uint8_t extra_dummy);
/**
* SPI1 register info get APIs. These APIs inform `spi_flash_timing_tuning.c` (driver layer) of the SPI1 flash settings.
* In this way, other components (e.g.: esp_flash driver) can get the info from it.
*/
void spi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time);
uint32_t spi_timing_config_get_flash_clock_reg(void);
#ifdef __cplusplus
}
#endif

View File

@ -27,6 +27,17 @@
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp_crypto_lock.h" // for locking flash encryption peripheral
#endif //CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#endif
static const char TAG[] = "spi_flash";
@ -58,7 +69,7 @@ static const char TAG[] = "spi_flash";
} while(0)
#endif // CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
#define IO_STR_LEN 7
#define IO_STR_LEN 10
static const char io_mode_str[][IO_STR_LEN] = {
"slowrd",
@ -67,9 +78,12 @@ static const char io_mode_str[][IO_STR_LEN] = {
"dio",
"qout",
"qio",
[6 ... 15] = "not used", // reserved io mode for future, not used currently.
"opi_str",
"opi_dtr",
};
_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_ll.h");
_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_types.h");
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
@ -247,6 +261,84 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
return rom_spiflash_api_funcs->end(chip, err);
}
// Note: This function is only used for internal. Only call this function to initialize the main flash.
// (flash chip on SPI1 CS0)
esp_err_t IRAM_ATTR esp_flash_init_main(esp_flash_t *chip)
{
// Chip init flow
// 1. Read chip id
// 2. (optional) Detect chip vendor
// 3. Get basic parameters of the chip (size, dummy count, etc.)
// 4. Init chip into desired mode (without breaking the cache!)
esp_err_t err = ESP_OK;
bool octal_mode = (chip->read_mode >= SPI_FLASH_OPI_FLAG);
if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_inst_t*)chip->host)->spi == NULL) {
return ESP_ERR_INVALID_ARG;
}
//read chip id
// This can indicate the MSPI support OPI, if the flash works on MSPI in OPI mode, we directly bypass read id.
uint32_t flash_id = 0;
if (octal_mode) {
// bypass the reading but get the flash_id from the ROM variable, to avoid resetting the chip to QSPI mode and read the ID again
flash_id = g_rom_flashchip.device_id;
} else {
int retries = 10;
do {
err = esp_flash_read_chip_id(chip, &flash_id);
} while (err == ESP_ERR_FLASH_NOT_INITIALISED && retries-- > 0);
}
if (err != ESP_OK) {
return err;
}
chip->chip_id = flash_id;
if (!esp_flash_chip_driver_initialized(chip)) {
// Detect chip_drv
err = detect_spi_flash_chip(chip);
if (err != ESP_OK) {
return err;
}
}
// Detect flash size
uint32_t size;
err = esp_flash_get_size(chip, &size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to get chip size");
return err;
}
if (chip->chip_drv->get_chip_caps == NULL) {
// chip caps get failed, pass the flash capability check.
ESP_LOGW(TAG, "get_chip_caps function pointer hasn't been initialized");
} else {
if (((chip->chip_drv->get_chip_caps(chip) & SPI_FLASH_CHIP_CAP_32MB_SUPPORT) == 0) && (size > (16 *1024 * 1024))) {
ESP_LOGW(TAG, "Detected flash size > 16 MB, but access beyond 16 MB is not supported for this flash model yet.");
size = (16 * 1024 * 1024);
}
}
ESP_LOGI(TAG, "flash io: %s", io_mode_str[chip->read_mode]);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
if (err == ESP_OK && !octal_mode) {
// Try to set the flash mode to whatever default mode was chosen
err = chip->chip_drv->set_io_mode(chip);
if (err == ESP_ERR_FLASH_NO_RESPONSE && !esp_flash_is_quad_mode(chip)) {
//some chips (e.g. Winbond) don't support to clear QE, treat as success
err = ESP_OK;
}
}
// Done: all fields on 'chip' are initialised
return rom_spiflash_api_funcs->end(chip, err);
}
static esp_err_t IRAM_ATTR read_id_core(esp_flash_t* chip, uint32_t* out_id, bool sanity_check)
{
bool installed = esp_flash_chip_driver_initialized(chip);

View File

@ -27,6 +27,7 @@
#include "hal/gpio_hal.h"
#include "esp_flash_internal.h"
#include "esp_rom_gpio.h"
#include "spi_flash_private.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
@ -56,6 +57,8 @@ esp_flash_t *esp_flash_default_chip = NULL;
#define DEFAULT_FLASH_SPEED ESP_FLASH_26MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_20M
#define DEFAULT_FLASH_SPEED ESP_FLASH_20MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_120M
#define DEFAULT_FLASH_SPEED ESP_FLASH_120MHZ
#else
#error Flash frequency not defined! Check the ``CONFIG_ESPTOOLPY_FLASHFREQ_*`` options.
#endif
@ -68,10 +71,10 @@ esp_flash_t *esp_flash_default_chip = NULL;
#define DEFAULT_FLASH_MODE SPI_FLASH_DIO
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
#define DEFAULT_FLASH_MODE SPI_FLASH_DOUT
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_FASTRD)
#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_SLOWRD)
#define DEFAULT_FLASH_MODE SPI_FLASH_SLOWRD
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR)
#define DEFAULT_FLASH_MODE SPI_FLASH_OPI_STR
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR)
#define DEFAULT_FLASH_MODE SPI_FLASH_OPI_DTR
#else
#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD
#endif
@ -294,6 +297,19 @@ esp_err_t esp_flash_init_default_chip(void)
cfg.iomux = esp_rom_efuse_get_flash_gpio_info() == 0 ? true : false;
#endif
#if CONFIG_ESPTOOLPY_OCT_FLASH
cfg.octal_mode_en = 1;
cfg.default_io_mode = DEFAULT_FLASH_MODE;
#endif
// For chips need time tuning, get value directely from system here.
#if SOC_SPI_MEM_SUPPORT_TIME_TUNING
if (spi_timine_config_flash_is_tuned()) {
cfg.using_timing_tuning = 1;
spi_timing_get_flash_timing_param(&cfg.timing_reg);
}
#endif // SOC_SPI_MEM_SUPPORT_TIME_TUNING
//the host is already initialized, only do init for the data and load it to the host
esp_err_t err = memspi_host_init_pointers(&esp_flash_default_host, &cfg);
if (err != ESP_OK) {
@ -302,7 +318,7 @@ esp_err_t esp_flash_init_default_chip(void)
// ROM TODO: account for non-standard default pins in efuse
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
err = esp_flash_init(&default_chip);
err = esp_flash_init_main(&default_chip);
if (err != ESP_OK) {
return err;
}

View File

@ -56,7 +56,6 @@
#include "cache_utils.h"
#include "esp_flash.h"
#include "esp_attr.h"
#include "spi_flash_private.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);
@ -518,7 +517,7 @@ out:
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
#if !CONFIG_SPI_FLASH_USE_LEGACY_IMPL
#if !CONFIG_ESPTOOLPY_OCT_FLASH
#if !CONFIG_ESPTOOLPY_OCT_FLASH // Test for encryption on opi flash, IDF-3852.
extern void spi_common_set_dummy_output(esp_rom_spiflash_read_mode_t mode);
extern void spi_dummy_len_fix(uint8_t spi, uint8_t freqdiv);
void IRAM_ATTR flash_rom_init(void)
@ -558,10 +557,6 @@ void IRAM_ATTR flash_rom_init(void)
read_mode = ESP_ROM_SPIFLASH_DIO_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_DOUT
read_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_FASTRD
read_mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_SLOWRD
read_mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
#endif
#endif //!CONFIG_IDF_TARGET_ESP32S2 && !CONFIG_IDF_TARGET_ESP32

View File

@ -68,3 +68,7 @@
#define SPI_FLASH_FASTRD_DUMMY_BITLEN 8
#define SPI_FLASH_SLOWRD_ADDR_BITLEN 24
#define SPI_FLASH_SLOWRD_DUMMY_BITLEN 0
#define SPI_FLASH_OPISTR_ADDR_BITLEN 32
#define SPI_FLASH_OPISTR_DUMMY_BITLEN 20
#define SPI_FLASH_OPIDTR_ADDR_BITLEN 32
#define SPI_FLASH_OPIDTR_DUMMY_BITLEN 40

View File

@ -30,15 +30,6 @@ typedef struct {
uint32_t page_program_timeout; ///< Timeout for page program operation
} flash_chip_op_timeout_t;
typedef struct flash_chip_dummy {
uint8_t dio_dummy_bitlen;
uint8_t qio_dummy_bitlen;
uint8_t qout_dummy_bitlen;
uint8_t dout_dummy_bitlen;
uint8_t fastrd_dummy_bitlen;
uint8_t slowrd_dummy_bitlen;
} flash_chip_dummy_t;
typedef enum {
SPI_FLASH_REG_STATUS = 1,
} spi_flash_register_t;
@ -215,6 +206,11 @@ struct spi_flash_chip_t {
* Get the capabilities of the flash chip. See SPI_FLASH_CHIP_CAP_* macros as reference.
*/
spi_flash_caps_t (*get_chip_caps)(esp_flash_t *chip);
/**
* Configure the host registers to use the specified read mode set in the ``chip->read_mode``.
*/
esp_err_t (*config_host_io_mode)(esp_flash_t *chip, uint32_t flags);
};
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used

View File

@ -370,14 +370,15 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
* transactions. Also prepare the command to be sent in read functions.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param addr_32bit Whether 32 bit commands will be used (Currently only W25Q256 and GD25Q256 are supported)
* @param flags Special rules to configure io mode, (i.e. Whether 32 bit commands will be used (Currently only W25Q256 and GD25Q256 are supported))
*
* @return
* - ESP_OK if success
* - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly
* - or other error passed from the ``configure_host_mode`` function of host driver
*/
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool addr_32bit);
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t flags);
#define SPI_FLASH_CONFIG_IO_MODE_32B_ADDR BIT(0)
/**
* @brief Handle explicit yield requests
@ -396,5 +397,15 @@ esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, uint32_t wip);
*/
esp_err_t spi_flash_chip_generic_suspend_cmd_conf(esp_flash_t *chip);
/**
*
* @brief Read the chip unique ID unsupported function.
*
* @param chip Pointer to SPI flash chip to use.
* @param flash_unique_id Pointer to store output unique id (Although this function is an unsupported function, but the parameter should be kept for the consistence of the function pointer).
* @return Always ESP_ERR_NOT_SUPPORTED.
*/
esp_err_t spi_flash_chip_generic_read_unique_id_none(esp_flash_t *chip, uint64_t* flash_unique_id);
/// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@ -25,3 +25,10 @@
* is not found.
*/
extern const spi_flash_chip_t esp_flash_chip_mxic;
/**
* MXIC OPI flash chip_drv, uses all the above functions for its operations. In
* default autodetection, this is used as a catchall if a more specific chip_drv
* is not found.
*/
extern const spi_flash_chip_t esp_flash_chip_mxic_opi;

View File

@ -26,23 +26,13 @@
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/spi_flash.h"
#endif
#include "esp_flash.h"
#include "hal/spi_flash_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This struct provide MSPI Flash necessary timing related config
*/
typedef struct {
uint8_t flash_clk_div; /*!< clock divider of Flash module. */
uint8_t flash_extra_dummy; /*!< timing required extra dummy length for Flash */
bool flash_setup_en; /*!< SPI0/1 Flash setup enable or not */
uint8_t flash_setup_time; /*!< SPI0/1 Flash setup time. This value should be set to register directly */
bool flash_hold_en; /*!< SPI0/1 Flash hold enable or not */
uint8_t flash_hold_time; /*!< SPI0/1 Flash hold time. This value should be set to register directly */
} spi_timing_flash_config_t;
/**
* @brief Register ROM functions and init flash device registers to make use of octal flash
*/
@ -82,10 +72,21 @@ void esp_mspi_pin_init(void);
void spi_flash_set_rom_required_regs(void);
/**
* @brief Get MSPI Flash necessary timing related config
* @param config see `spi_timing_flash_config_t`
* @brief Initialize main flash
* @param chip Pointer to main SPI flash(SPI1 CS0) chip to use..
*/
void spi_timing_get_flash_regs(spi_timing_flash_config_t *config);
esp_err_t esp_flash_init_main(esp_flash_t *chip);
/**
* @brief Should be only used by SPI1 Flash driver to know the necessary timing registers
* @param out_timing_config Pointer to timing_tuning parameters.
*/
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config);
/**
* @brief Judge if the flash in tuned
*/
bool spi_timine_config_flash_is_tuned(void);
#ifdef __cplusplus
}

View File

@ -18,3 +18,6 @@ entries:
if IDF_TARGET_ESP32S3 = y && ESPTOOLPY_OCT_FLASH = y:
spi_flash_oct_flash_init (noflash)
if IDF_TARGET_ESP32S3 = y :
spi_flash_chip_mxic_opi (noflash)

View File

@ -207,19 +207,47 @@ esp_err_t memspi_host_set_write_protect(spi_flash_host_inst_t *host, bool wp)
// This is the simple case where the hardware has no other requirements than the size and page boundary
int memspi_host_write_data_slicer(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size)
{
uint32_t slicer_flag = ((spi_flash_hal_context_t*)host)->slicer_flags;
uint32_t align_addr = address;
if (slicer_flag & SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR) {
if (((align_addr % 2) != 0) && ((len % 2) != 0)) {
align_addr -= 1;
len += 1;
} else if (((align_addr % 2) != 0) && ((len % 2) == 0)) {
align_addr -= 1;
len += 2;
} else if (((align_addr % 2) == 0) && ((len % 2) != 0)) {
len += 1;
}
}
uint32_t end_bound = (align_addr/page_size + 1) * page_size;
// Shouldn't program cross the page, or longer than SPI_FLASH_HAL_MAX_WRITE_BYTES
uint32_t max_len = MIN(end_bound - align_addr, SPI_FLASH_HAL_MAX_WRITE_BYTES);
*align_address = address;
*align_address = align_addr;
return MIN(max_len, len);
}
int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size)
{
// Shouldn't read longer than SPI_FLASH_HAL_MAX_READ_BYTES
uint32_t slicer_flag = ((spi_flash_hal_context_t*)host)->slicer_flags;
uint32_t align_addr = address;
if (slicer_flag & SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR) {
if (((align_addr % 2) != 0) && ((len % 2) != 0)) {
align_addr -= 1;
len += 1;
} else if (((align_addr % 2) != 0) && ((len % 2) == 0)) {
align_addr -= 1;
len += 2;
} else if (((align_addr % 2) == 0) && ((len % 2) != 0)) {
len += 1;
}
}
uint32_t max_len = SPI_FLASH_HAL_MAX_READ_BYTES;
*align_address = address;
*align_address = align_addr;
return MIN(max_len, len);
}

View File

@ -83,4 +83,5 @@ const spi_flash_chip_t esp_flash_chip_boya = {
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id,
.get_chip_caps = spi_flash_chip_boya_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,
};

View File

@ -47,6 +47,9 @@ static const spi_flash_chip_t *default_registered_chips[] = {
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP
&esp_flash_chip_boya,
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
&esp_flash_chip_mxic_opi,
#endif
// Default chip drivers that will accept all chip ID.
// FM, Winbond and XMC chips are supposed to be supported by this chip driver.

View File

@ -144,4 +144,5 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id,
.get_chip_caps = spi_flash_chip_gd_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,
};

View File

@ -21,6 +21,15 @@
#include "esp_log.h"
#include "esp_attr.h"
typedef struct flash_chip_dummy {
uint8_t dio_dummy_bitlen;
uint8_t qio_dummy_bitlen;
uint8_t qout_dummy_bitlen;
uint8_t dout_dummy_bitlen;
uint8_t fastrd_dummy_bitlen;
uint8_t slowrd_dummy_bitlen;
} flash_chip_dummy_t;
// These parameters can be placed in the ROM. For now we use the code in IDF.
DRAM_ATTR const static flash_chip_dummy_t default_flash_chip_dummy = {
.dio_dummy_bitlen = SPI_FLASH_DIO_DUMMY_BITLEN,
@ -191,9 +200,10 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
const uint32_t page_size = chip->chip_drv->page_size;
uint32_t align_address;
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
uint32_t config_io_flags = 0;
// Configure the host, and return
err = spi_flash_chip_generic_config_host_io_mode(chip, false);
err = chip->chip_drv->config_host_io_mode(chip, config_io_flags);
if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "configure host io mode failed - unsupported");
@ -439,13 +449,14 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return (timeout_us > 0) ? ESP_OK : ESP_ERR_TIMEOUT;
}
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool addr_32bit)
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t flags)
{
uint32_t dummy_cyclelen_base;
uint32_t addr_bitlen;
uint32_t read_command;
bool conf_required = false;
esp_flash_io_mode_t read_mode = chip->read_mode;
bool addr_32bit = (flags & SPI_FLASH_CONFIG_IO_MODE_32B_ADDR);
switch (read_mode & 0xFFFF) {
case SPI_FLASH_QIO:
@ -544,6 +555,12 @@ esp_err_t spi_flash_chip_generic_read_unique_id(esp_flash_t *chip, uint64_t* fla
return err;
}
esp_err_t spi_flash_chip_generic_read_unique_id_none(esp_flash_t *chip, uint64_t* flash_unique_id)
{
// For flash doesn't support read unique id.
return ESP_ERR_NOT_SUPPORTED;
}
spi_flash_caps_t spi_flash_chip_generic_get_caps(esp_flash_t *chip)
{
// For generic part flash capability, take the XMC chip as reference.
@ -600,6 +617,7 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id,
.get_chip_caps = spi_flash_chip_generic_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,
};
#ifndef CONFIG_SPI_FLASH_ROM_IMPL

View File

@ -107,4 +107,5 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id,
.get_chip_caps = spi_flash_chip_issi_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,
};

View File

@ -16,13 +16,10 @@
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#include "esp_log.h"
#include "string.h"
#include <sys/param.h> // For MIN/MAX
#include "hal/spi_flash_hal.h"
/* Driver for MXIC flash chip */
extern flash_chip_dummy_t *rom_flash_chip_dummy;
esp_err_t spi_flash_chip_mxic_probe(esp_flash_t *chip, uint32_t flash_id)
{
/* Check manufacturer and product IDs match our desired masks */
@ -30,6 +27,10 @@ esp_err_t spi_flash_chip_mxic_probe(esp_flash_t *chip, uint32_t flash_id)
if (flash_id >> 16 != MFG_ID) {
return ESP_ERR_NOT_FOUND;
}
if (chip->read_mode >= SPI_FLASH_OPI_FLAG) {
// The code here serve for ordinary mxic chip. If opi mode has been selected, go `spi_flash_chip_mxic_opi.c`
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
@ -44,50 +45,6 @@ esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t
static const char chip_name[] = "mxic";
esp_err_t spi_flash_chip_mxic_read_unique_id(esp_flash_t *chip, uint64_t* flash_unique_id)
{
//MXIC not support read unique id.
ESP_LOGE(chip_name, "chip %s doesn't support reading unique id", chip->chip_drv->name);
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t spi_flash_chip_mxic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err = ESP_OK;
const uint32_t page_size = chip->chip_drv->page_size;
uint32_t align_address;
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
// Configure the host, and return
uint32_t addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN;
uint32_t dummy_cyclelen_base = rom_flash_chip_dummy->fastrd_dummy_bitlen;;
uint32_t read_command = CMD_FASTRD;
uint32_t read_mode = SPI_FLASH_FASTRD;
err = chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, read_mode);
if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(chip_name, "configure host io mode failed - unsupported");
return err;
}
while (err == ESP_OK && length > 0) {
memset(temp_buffer, 0xFF, sizeof(temp_buffer));
uint32_t read_len = chip->host->driver->read_data_slicer(chip->host, address, length, &align_address, page_size);
uint32_t left_off = address - align_address;
uint32_t data_len = MIN(align_address + read_len, address + length) - address;
err = chip->host->driver->read(chip->host, temp_buffer, align_address, read_len);
memcpy(buffer, temp_buffer + left_off, data_len);
address += data_len;
buffer = (void *)((intptr_t)buffer + data_len);
length = length - data_len;
}
return err;
}
spi_flash_caps_t spi_flash_chip_mxic_get_caps(esp_flash_t *chip)
{
spi_flash_caps_t caps_flags = 0;
@ -132,6 +89,7 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.read_reg = spi_flash_chip_mxic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_mxic_read_unique_id,
.read_unique_id = spi_flash_chip_generic_read_unique_id_none,
.get_chip_caps = spi_flash_chip_mxic_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,
};

View File

@ -0,0 +1,420 @@
// 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 <stdlib.h>
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#include "esp_log.h"
#include "string.h"
#include <sys/param.h> // For MIN/MAX
#include "hal/spi_flash_hal.h"
#define CMD_OPI_FLASH_MXIC(cmd) ((((~(cmd) & 0xff) << 8)) | ((cmd) & 0xff))
#define CMD_OPI_FLASH_MXIC_CHIP_ERASE 0x9F60
#define CMD_OPI_FLASH_MXIC_READ_STR 0x13EC
#define CMD_OPI_FLASH_MXIC_READ_DTR 0x11EE
#define CMD_OPI_FLASH_MXIC_RDCR2 0x8E71
#define CMD_OPI_FLASH_MXIC_WRCR2 0x8D72
/* Driver for MXIC OPI flash chip */
static const char chip_name[] = "mxic (opi)";
esp_err_t spi_flash_chip_mxic_opi_probe(esp_flash_t *chip, uint32_t flash_id)
{
/* Check manufacturer and product IDs match our desired masks */
const uint8_t MFG_ID = 0xC2;
if (flash_id >> 16 != MFG_ID) {
return ESP_ERR_NOT_FOUND;
}
if (chip->read_mode < SPI_FLASH_OPI_FLAG) {
// The code here serve for opi flash under opi mode only, for ordinary mxic chip, go `spi_flash_chip_mxic.c`
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
spi_flash_caps_t spi_flash_chip_mxic_opi_get_caps(esp_flash_t *chip)
{
spi_flash_caps_t caps_flags = 0;
caps_flags |= SPI_FLASH_CHIP_CAP_32MB_SUPPORT;
// flash-suspend is not supported yet. // IDF-3852
// reading unique id is not supported.
return caps_flags;
}
esp_err_t spi_flash_chip_mxic_opi_set_write_protect(esp_flash_t *chip, bool write_protect)
{
esp_err_t err = ESP_OK;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
spi_flash_trans_t t = {};
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
if(write_protect) {
t.command = CMD_OPI_FLASH_MXIC(CMD_WRDI);
} else {
t.command = CMD_OPI_FLASH_MXIC(CMD_WREN);
}
err = chip->host->driver->common_command(chip->host, &t);
}
bool wp_read;
err = chip->chip_drv->get_chip_write_protect(chip, &wp_read);
if (err == ESP_OK && wp_read != write_protect) {
err = ESP_ERR_NOT_FOUND;
}
return err;
}
static void spi_flash_chip_mxic_opi_get_data_length_zoom(esp_flash_io_mode_t io_mode, uint32_t *length_zoom)
{
/* Under STR mode, one byte occupies one single clock. While under DTR mode, one byte occupies half clock.
For exmaple, if an operation needs 3 clock dummy, host send 3 dummy bytes under STR mode, while 6 dummy bytes under DTR mode.
Therefore, we need to adjust data zoom to fit the clock here. */
assert((io_mode == SPI_FLASH_OPI_STR) || (io_mode == SPI_FLASH_OPI_DTR));
*length_zoom = (io_mode == SPI_FLASH_OPI_STR) ? 1 : 2;
}
esp_err_t spi_flash_chip_mxic_opi_read_id(esp_flash_t *chip, uint32_t* out_chip_id)
{
uint64_t id_buf = 0;
uint32_t length_zoom;
spi_flash_chip_mxic_opi_get_data_length_zoom(chip->read_mode, &length_zoom);
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC(CMD_RDID),
.miso_len = 3 * length_zoom,
.dummy_bitlen = 4 * length_zoom,
.address_bitlen = 32,
.miso_data = ((uint8_t*) &id_buf),
};
chip->host->driver->common_command(chip->host, &t);
if(chip->read_mode == SPI_FLASH_OPI_DTR) {
// Adjust the id_buf in DTR mode, because in DTR mode, the data back in STR rule.
// So it looks like [MD, MD, MT, MT, MID, MID], adjust it to [MD, MT, MID] here.
ESP_EARLY_LOGV(chip_name, "raw_chip_id: %llx\n", id_buf);
id_buf = (id_buf & 0xff) | ((id_buf & 0xff0000) >> 8) | ((id_buf & 0xff00000000) >> 16);
} else {
ESP_EARLY_LOGV(chip_name, "raw_chip_id: %X\n", id_buf);
}
uint32_t raw_flash_id = __builtin_bswap32(id_buf);
if (raw_flash_id == 0xFFFFFF || raw_flash_id == 0) {
ESP_EARLY_LOGE(chip_name, "no response\n");
return ESP_ERR_FLASH_NO_RESPONSE;
}
*out_chip_id = (raw_flash_id >> 8);
ESP_EARLY_LOGV(chip_name, "chip_id: %X\n", *out_chip_id);
return ESP_OK;
}
esp_err_t spi_flash_chip_mxic_opi_read_reg(esp_flash_t *chip, spi_flash_register_t reg_id, uint32_t* out_reg)
{
uint32_t stat_buf = 0;
uint32_t length_zoom;
spi_flash_chip_mxic_opi_get_data_length_zoom(chip->read_mode, &length_zoom);
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC(CMD_RDSR),
.miso_data = ((uint8_t*) &stat_buf),
.miso_len = 1 * length_zoom,
.address_bitlen = 32,
.dummy_bitlen = 4 * length_zoom,
};
esp_err_t err = chip->host->driver->common_command(chip->host, &t);
if (err != ESP_OK) {
return err;
}
// For DTR mode, RDSR result like [SR1, SR1], just keeping one SR1.
*out_reg = (stat_buf & 0xff);
return ESP_OK;
}
esp_err_t spi_flash_chip_mxic_opi_get_write_protect(esp_flash_t *chip, bool *out_write_protected)
{
esp_err_t err = ESP_OK;
uint32_t status;
assert(out_write_protected!=NULL);
err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &status);
if (err != ESP_OK) {
return err;
}
*out_write_protected = ((status & SR_WREN) == 0);
return err;
}
esp_err_t spi_flash_chip_mxic_opi_erase_chip(esp_flash_t *chip)
{
esp_err_t err;
err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
// Do erase chip here.
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC_CHIP_ERASE,
};
err = chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
#else
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->chip_erase_timeout);
#endif
}
// Ensure WEL is 0, even if the erase failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
esp_err_t spi_flash_chip_mxic_opi_erase_sector(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC(CMD_SECTOR_ERASE_4B),
.address_bitlen = 32,
.address = start_address,
};
err = chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
#else
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->sector_erase_timeout);
#endif
}
// Ensure WEL is 0, even if the erase failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
esp_err_t spi_flash_chip_mxic_opi_erase_block(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC(CMD_LARGE_BLOCK_ERASE_4B),
.address_bitlen = 32,
.address = start_address,
};
err = chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
#else
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->block_erase_timeout);
#endif
}
// Ensure WEL is 0, even if the erase failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
esp_err_t spi_flash_chip_mxic_opi_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
// Perform the actual Page Program command
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC(CMD_PROGRAM_PAGE_4B),
.address_bitlen = 32,
.address = address,
.mosi_len = length,
.mosi_data = buffer,
};
chip->host->driver->common_command(chip->host, &t);
chip->busy = 1;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
}
// Ensure WEL is 0, even if the page program failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
esp_err_t spi_flash_chip_mxic_opi_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err = ESP_OK;
const uint32_t page_size = chip->chip_drv->page_size;
uint32_t align_address;
uint8_t temp_buffer[64]; //spiflash hal max length of write no longer than 64byte
while (err == ESP_OK && length > 0) {
memset(temp_buffer, 0xFF, sizeof(temp_buffer));
uint32_t page_len = chip->host->driver->write_data_slicer(chip->host, address, length, &align_address, page_size);
uint32_t left_off = address - align_address;
uint32_t write_len = MIN(align_address + page_len, address + length) - address;
memcpy(temp_buffer + left_off, buffer, write_len);
err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK && length > 0) {
err = chip->chip_drv->program_page(chip, temp_buffer, align_address, page_len);
address += write_len;
buffer = (void *)((intptr_t)buffer + write_len);
length -= write_len;
}
}
// The caller is responsible to do host->driver->flush_cache, because this function may be
// called in small pieces. Frequency call of flush cache will do harm to the performance.
return err;
}
esp_err_t spi_flash_chip_mxic_opi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
{
uint32_t stat_buf = 0;
uint32_t length_zoom;
spi_flash_chip_mxic_opi_get_data_length_zoom(chip->read_mode, &length_zoom);
spi_flash_trans_t t = {
.command = CMD_OPI_FLASH_MXIC_RDCR2,
.dummy_bitlen = 4 * length_zoom,
.miso_data = ((uint8_t*) &stat_buf),
.miso_len = 1 * length_zoom,
.address_bitlen = 32,
};
esp_err_t err = chip->host->driver->common_command(chip->host, &t);
if (err != ESP_OK) {
return err;
}
// For DTR mode, RDSR result like [CR1, CR1], just keeping one CR1.
switch (stat_buf & 0xff)
{
case 0x1:
*out_io_mode = SPI_FLASH_OPI_STR;
break;
case 0x2:
*out_io_mode = SPI_FLASH_OPI_DTR;
break;
default:
// wrong mode.
*out_io_mode = 0;
break;
}
if (*out_io_mode != chip->read_mode) {
// Current chip mode is not the mode we configured.
*out_io_mode = 0;
}
return ESP_OK;
}
esp_err_t spi_flash_chip_xmic_opi_set_io_mode(esp_flash_t *chip)
{
// TODO: configure opi flash chip set io mode, only useful for external flash currently.
// For main flash, we already set io mode when chip starts up. But for external flash,
// We need to set mode when flash initialized, so keeping this for future usage.
return ESP_OK;
}
// This function should only be called after opi mode initialization. So, only configure for OPI-STR/OPI-DTR mode
// not support other mode in this file, return `ESP_ERR_FLASH_NOT_INITIALISED` directely.
esp_err_t spi_flash_chip_xmic_opi_config_host_io_mode(esp_flash_t *chip, uint32_t flags)
{
uint32_t dummy_cyclelen_base;
uint32_t addr_bitlen;
uint32_t read_command;
esp_flash_io_mode_t read_mode = chip->read_mode;
switch (read_mode & 0xFFFF) {
case SPI_FLASH_OPI_STR:
addr_bitlen = SPI_FLASH_OPISTR_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_OPISTR_DUMMY_BITLEN;
read_command = CMD_OPI_FLASH_MXIC_READ_STR;
break;
case SPI_FLASH_OPI_DTR:
addr_bitlen = SPI_FLASH_OPIDTR_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_OPIDTR_DUMMY_BITLEN;
read_command = CMD_OPI_FLASH_MXIC_READ_DTR;
break;
default:
return ESP_ERR_FLASH_NOT_INITIALISED;
}
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, read_mode);
}
// Most of mxic opi implementations are totally different from that is generic.
// Replace them to opi implementation.
const spi_flash_chip_t esp_flash_chip_mxic_opi = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_mxic_opi_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
.erase_chip = spi_flash_chip_mxic_opi_erase_chip,
.erase_sector = spi_flash_chip_mxic_opi_erase_sector,
.erase_block = spi_flash_chip_mxic_opi_erase_block,
.sector_size = 4 * 1024,
.block_erase_size = 64 * 1024,
.get_chip_write_protect = spi_flash_chip_mxic_opi_get_write_protect,
.set_chip_write_protect = spi_flash_chip_mxic_opi_set_write_protect,
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
.set_protected_regions = NULL,
.read = spi_flash_chip_generic_read,
.write = spi_flash_chip_mxic_opi_write,
.program_page = spi_flash_chip_mxic_opi_page_program,
.page_size = 256,
.write_encrypted = spi_flash_chip_generic_write_encrypted,
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_xmic_opi_set_io_mode,
.get_io_mode = spi_flash_chip_mxic_opi_get_io_mode,
.read_id = spi_flash_chip_mxic_opi_read_id,
.read_reg = spi_flash_chip_mxic_opi_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id_none,
.get_chip_caps = spi_flash_chip_mxic_opi_get_caps,
.config_host_io_mode = spi_flash_chip_xmic_opi_config_host_io_mode,
};

View File

@ -48,9 +48,13 @@ esp_err_t spi_flash_chip_winbond_read(esp_flash_t *chip, void *buffer, uint32_t
const uint32_t page_size = chip->chip_drv->page_size;
uint32_t align_address;
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
uint32_t config_io_flags = 0;
// Configure the host, and return
err = spi_flash_chip_generic_config_host_io_mode(chip, REGION_32BIT(address, length));
if (REGION_32BIT(address, length)) {
config_io_flags |= SPI_FLASH_CONFIG_IO_MODE_32B_ADDR;
}
err = chip->chip_drv->config_host_io_mode(chip, config_io_flags);
if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "configure host io mode failed - unsupported");
@ -192,6 +196,7 @@ const spi_flash_chip_t esp_flash_chip_winbond = {
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id,
.get_chip_caps = spi_flash_chip_winbond_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,
};

View File

@ -14,6 +14,7 @@
#include "soc/spi_mem_reg.h"
#include "soc/io_mux_reg.h"
#include "spi_flash_private.h"
#include "soc/soc.h"
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spi_timing_config.h"
#endif
@ -462,17 +463,24 @@ void spi_timing_enter_mspi_high_speed_mode(bool control_spi1)
/**
* Should be only used by SPI1 Flash driver to know the necessary timing registers
*/
void spi_timing_get_flash_regs(spi_timing_flash_config_t *config)
{
config->flash_clk_div = get_flash_clock_divider();
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
config->flash_extra_dummy = s_flash_best_timing_tuning_config.extra_dummy_len;
#else
config->flash_extra_dummy = 0;
#endif
config->flash_setup_en = REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_SETUP);
config->flash_setup_time = REG_GET_FIELD(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME);
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
{
// Get clock configuration directly from system.
out_timing_config->clock_config.spimem.val = spi_timing_config_get_flash_clock_reg();
config->flash_hold_en = REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD);
config->flash_hold_time = REG_GET_FIELD(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME);
// Get extra dummy length here. Therefore, no matter what freq, or mode.
// If it needs tuning, it will return correct extra dummy len. If no tuning, it will return 0.
out_timing_config->extra_dummy = s_flash_best_timing_tuning_config.extra_dummy_len;
// Get CS setup/hold value here.
spi_timing_config_get_cs_timing(&out_timing_config->cs_setup, &out_timing_config->cs_hold);
}
#else
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
{
// This function shouldn't be called if timing tuning is not used.
abort();
}
#endif // SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING

View File

@ -727,6 +727,7 @@ static void write_large_buffer(const esp_partition_t *part, const uint8_t *sourc
static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length);
// Internal functions for testing, from esp_flash_api.c
#if !CONFIG_ESPTOOLPY_OCT_FLASH
esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe);
esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe);
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
@ -801,16 +802,17 @@ IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(const esp_partition_t* part)
// `spi_flash_common_set_io_mode` and then run this test.
FLASH_TEST_CASE_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
FLASH_TEST_CASE_3_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
#endif //CONFIG_ESPTOOLPY_OCT_FLASH
void test_permutations_part(const flashtest_config_t* config, esp_partition_t* part, void* source_buf, size_t length)
{
if (config->host_id != -1) {
esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN;
while (speed != ESP_FLASH_SPEED_MAX) {
while (speed != ESP_FLASH_120MHZ) {
//test io_mode in the inner loop to test QE set/clear function, since
//the io mode will switch frequently.
esp_flash_io_mode_t io_mode = SPI_FLASH_READ_MODE_MIN;
while (io_mode != SPI_FLASH_READ_MODE_MAX) {
while (io_mode != SPI_FLASH_QIO + 1) {
if (io_mode > SPI_FLASH_FASTRD &&
!SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(config->host_id)) {
io_mode++;

View File

@ -28,20 +28,21 @@
#include "esp_heap_caps.h"
#if CONFIG_IDF_TARGET_ESP32
#include <esp32/rom/spi_flash.h>
#include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include <esp32s2/rom/spi_flash.h>
#include "esp32s2/rom/spi_flash.h"
#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>
#include "esp32c3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/spi_flash.h"
#endif
#define MIN_BLOCK_SIZE 12
/* Base offset in flash for tests. */
static size_t start;
extern spiflash_legacy_data_t *rom_spiflash_legacy_data;
static void setup_tests(void)
{
@ -151,22 +152,24 @@ TEST_CASE("Test spi_flash_read", "[spi_flash][esp_flash]")
#endif
}
#if !CONFIG_ESPTOOLPY_OCT_FLASH
extern void spi_common_set_dummy_output(esp_rom_spiflash_read_mode_t mode);
extern void spi_dummy_len_fix(uint8_t spi, uint8_t freqdiv);
static void IRAM_ATTR fix_rom_func(void)
{
uint32_t freqdiv = 0;
uint32_t vendor_id = (rom_spiflash_legacy_data->chip.device_id >> 16);
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M && !CONFIG_ESPTOOLPY_OCT_FLASH
freqdiv = 1;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M && CONFIG_ESPTOOLPY_OCT_FLASH
freqdiv = 2;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
freqdiv = 2;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_26M
freqdiv = 3;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_20M
freqdiv = 4;
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
freqdiv = 2;
#endif
#if CONFIG_IDF_TARGET_ESP32
@ -194,24 +197,20 @@ static void IRAM_ATTR fix_rom_func(void)
read_mode = ESP_ROM_SPIFLASH_DIO_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_DOUT
read_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_FASTRD
read_mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_SLOWRD
read_mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR
read_mode = ESP_ROM_SPIFLASH_OPI_STR_MODE;
#elif CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR
read_mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
#endif
#if !CONFIG_IDF_TARGET_ESP32S2 && !CONFIG_IDF_TARGET_ESP32
spi_common_set_dummy_output(read_mode);
#endif //!CONFIG_IDF_TARGET_ESP32S2
esp_rom_spiflash_config_clk(freqdiv, 1);
if (vendor_id == 0xc2) {
// If the flash vendor is mxic, it dones't support the read mode mentioned above.
// So, do nothing
} else {
esp_rom_spiflash_config_readmode(read_mode);
}
}
#if !CONFIG_ESPTOOLPY_OCT_FLASH
esp_rom_spiflash_config_readmode(read_mode);
#endif
}
static void IRAM_ATTR test_write(int dst_off, int src_off, int len)
{
@ -233,9 +232,8 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len)
fill(dst_gold + dst_off, src_off, len);
}
ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len));
#if !CONFIG_ESPTOOLPY_OCT_FLASH
fix_rom_func();
#endif
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf));