mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-19 07:55:54 +00:00
esp_flash: fix set qe bit and write command issues
There used to be dummy phase before out phase in common command transactions. This corrupts the data. The code before never actually operate (clear) the QE bit, once it finds the QE bit is set. It's hard to check whether the QE set/disable functions work well. This commit: 1. Cancel the dummy phase 2. Set and clear the QE bit according to chip settings, allowing tests for QE bits. However for some chips (Winbond for example), it's not forced to clear the QE bit if not able to. 3. Also refactor to allow chip_generic and other chips to share the same code to read and write qe bit; let common command and read command share configure_host_io_mode. 4. Rename read mode to io mode since maybe we will write data with quad mode one day.
This commit is contained in:
@@ -3,25 +3,31 @@ if(BOOTLOADER_BUILD)
|
||||
# Bootloader needs SPIUnlock from this file, but doesn't
|
||||
# need other parts of this component
|
||||
set(srcs "spi_flash_rom_patch.c")
|
||||
set(cache_srcs "")
|
||||
else()
|
||||
set(srcs
|
||||
set(cache_srcs
|
||||
"cache_utils.c"
|
||||
"flash_mmap.c"
|
||||
"flash_ops.c"
|
||||
)
|
||||
set(srcs
|
||||
"partition.c"
|
||||
"spi_flash_rom_patch.c"
|
||||
)
|
||||
# New implementation
|
||||
list(APPEND cache_srcs
|
||||
"esp_flash_api.c"
|
||||
"esp_flash_spi_init.c"
|
||||
"spi_flash_os_func_app.c"
|
||||
"spi_flash_os_func_noos.c"
|
||||
)
|
||||
list(APPEND srcs
|
||||
"spi_flash_chip_drivers.c"
|
||||
"spi_flash_chip_generic.c"
|
||||
"spi_flash_chip_issi.c"
|
||||
"spi_flash_os_func_app.c"
|
||||
"spi_flash_os_func_noos.c"
|
||||
"memspi_host_driver.c"
|
||||
"esp_flash_api.c"
|
||||
"esp_flash_spi_init.c"
|
||||
)
|
||||
list(APPEND srcs ${cache_srcs})
|
||||
set(priv_requires bootloader_support app_update soc)
|
||||
endif()
|
||||
|
||||
@@ -30,3 +36,7 @@ idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
# Avoid cache miss by unexpected inlineing when built by -Os
|
||||
set_source_files_properties(${cache_srcs} PROPERTIES COMPILE_FLAGS
|
||||
"-fno-inline-functions -fno-inline-small-functions -fno-inline-functions-called-once")
|
||||
|
@@ -60,7 +60,7 @@ static const char io_mode_str[][IO_STR_LEN] = {
|
||||
"qio",
|
||||
};
|
||||
|
||||
_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_read_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_ll.h");
|
||||
|
||||
|
||||
/* Static function to notify OS of a new SPI flash operation.
|
||||
@@ -139,38 +139,51 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
|
||||
|
||||
if (err == ESP_OK) {
|
||||
// Try to set the flash mode to whatever default mode was chosen
|
||||
err = chip->chip_drv->set_read_mode(chip);
|
||||
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 spiflash_end(chip, err);
|
||||
}
|
||||
|
||||
//this is not public, but useful in unit tests
|
||||
esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id)
|
||||
{
|
||||
esp_err_t err = spiflash_start(chip);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner
|
||||
// function fails if it sees all-ones or all-zeroes.)
|
||||
err = chip->host->read_id(chip->host, flash_id);
|
||||
|
||||
if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors
|
||||
uint32_t new_id;
|
||||
err = chip->host->read_id(chip->host, &new_id);
|
||||
if (err == ESP_OK && (new_id != *flash_id)) {
|
||||
err = ESP_ERR_FLASH_NOT_INITIALISED;
|
||||
}
|
||||
}
|
||||
|
||||
return spiflash_end(chip, err);
|
||||
}
|
||||
|
||||
static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t flash_id;
|
||||
int retries = 10;
|
||||
do {
|
||||
err = spiflash_start(chip);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner
|
||||
// function fails if it sees all-ones or all-zeroes.)
|
||||
err = chip->host->read_id(chip->host, &flash_id);
|
||||
|
||||
if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors
|
||||
uint32_t new_id;
|
||||
err = chip->host->read_id(chip->host, &new_id);
|
||||
if (err == ESP_OK && (new_id != flash_id)) {
|
||||
err = ESP_ERR_FLASH_NOT_INITIALISED;
|
||||
}
|
||||
}
|
||||
|
||||
err = spiflash_end(chip, err);
|
||||
} while (err != ESP_OK && retries-- > 0);
|
||||
err = esp_flash_read_chip_id(chip, &flash_id);
|
||||
} while (err == ESP_ERR_FLASH_NOT_INITIALISED && retries-- > 0);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Detect the chip and set the chip_drv structure for it
|
||||
const spi_flash_chip_t **drivers = esp_flash_registered_chips;
|
||||
@@ -617,6 +630,36 @@ esp_err_t IRAM_ATTR esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address
|
||||
return spi_flash_read_encrypted(address, out_buffer, length);
|
||||
}
|
||||
|
||||
// test only, non-public
|
||||
IRAM_ATTR esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe)
|
||||
{
|
||||
VERIFY_OP(get_io_mode);
|
||||
esp_flash_io_mode_t io_mode;
|
||||
|
||||
esp_err_t err = spiflash_start(chip);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
err = chip->chip_drv->get_io_mode(chip, &io_mode);
|
||||
err = spiflash_end(chip, err);
|
||||
if (err == ESP_OK) {
|
||||
*qe = (io_mode == SPI_FLASH_QOUT);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
|
||||
{
|
||||
VERIFY_OP(set_io_mode);
|
||||
chip->read_mode = (qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD);
|
||||
esp_err_t err = spiflash_start(chip);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
err = chip->chip_drv->set_io_mode(chip);
|
||||
return spiflash_end(chip, err);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
|
||||
esp_err_t esp_flash_app_disable_protect(bool disable)
|
||||
{
|
||||
|
@@ -62,7 +62,7 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
|
||||
esp_flash_t *esp_flash_default_chip = NULL;
|
||||
|
||||
|
||||
static IRAM_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux)
|
||||
static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux)
|
||||
{
|
||||
//Not using spicommon_cs_initialize since we don't want to put the whole
|
||||
//spi_periph_signal into the DRAM. Copy these data from flash before the
|
||||
|
@@ -63,7 +63,7 @@ struct esp_flash_t {
|
||||
const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure. Call ``esp_flash_init_os_functions()`` to setup this field, after the host is properly initialized.
|
||||
void *os_func_data; ///< Pointer to argument for os-specific hooks. Left NULL and will be initialized with ``os_func``.
|
||||
|
||||
esp_flash_read_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.
|
||||
esp_flash_io_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.
|
||||
uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation.
|
||||
};
|
||||
|
||||
@@ -286,6 +286,22 @@ esp_err_t esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address, void *ou
|
||||
extern esp_flash_t *esp_flash_default_chip;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Utility Functions
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Returns true if chip is configured for Quad I/O or Quad Fast Read.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
|
||||
*
|
||||
* @return true if flash works in quad mode, otherwise false
|
||||
*/
|
||||
static inline bool esp_flash_is_quad_mode(const esp_flash_t *chip)
|
||||
{
|
||||
return (chip->read_mode == SPI_FLASH_QIO) || (chip->read_mode == SPI_FLASH_QOUT);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -22,7 +22,7 @@ typedef struct {
|
||||
spi_host_device_t host_id; ///< Bus to use
|
||||
int cs_id; ///< CS pin (signal) to use
|
||||
int cs_io_num; ///< GPIO pin to output the CS signal
|
||||
esp_flash_read_mode_t io_mode; ///< IO mode to read from the Flash
|
||||
esp_flash_io_mode_t io_mode; ///< IO mode to read from the Flash
|
||||
esp_flash_speed_t speed; ///< Speed of the Flash clock
|
||||
int input_delay_ns; ///< Input delay of the data pins, in ns. Set to 0 if unknown.
|
||||
} esp_flash_spi_device_config_t;
|
||||
|
@@ -32,7 +32,7 @@
|
||||
.read = spi_flash_hal_read, \
|
||||
.max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES, \
|
||||
.host_idle = spi_flash_hal_host_idle, \
|
||||
.configure_host_read_mode = spi_flash_hal_configure_host_read_mode, \
|
||||
.configure_host_io_mode = spi_flash_hal_configure_host_io_mode, \
|
||||
.poll_cmd_done = spi_flash_hal_poll_cmd_done, \
|
||||
.flush_cache = memspi_host_flush_cache, \
|
||||
}
|
||||
|
@@ -149,7 +149,13 @@ struct spi_flash_chip_t {
|
||||
*
|
||||
* Can return ESP_ERR_FLASH_UNSUPPORTED_HOST or ESP_ERR_FLASH_UNSUPPORTED_CHIP if the specified mode is unsupported.
|
||||
*/
|
||||
esp_err_t (*set_read_mode)(esp_flash_t *chip);
|
||||
esp_err_t (*set_io_mode)(esp_flash_t *chip);
|
||||
|
||||
/*
|
||||
* Get whether the Quad Enable (QE) is set. (*out_io_mode)=SPI_FLASH_QOUT if
|
||||
* enabled, otherwise disabled
|
||||
*/
|
||||
esp_err_t (*get_io_mode)(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
|
||||
};
|
||||
|
||||
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used
|
||||
|
@@ -213,7 +213,21 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_m
|
||||
* - ESP_ERR_TIMEOUT if not idle before timeout
|
||||
* - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver
|
||||
*/
|
||||
esp_err_t spi_flash_chip_generic_set_read_mode(esp_flash_t *chip);
|
||||
esp_err_t spi_flash_chip_generic_set_io_mode(esp_flash_t *chip);
|
||||
|
||||
/**
|
||||
* Get whether the Quad Enable (QE) is set.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
|
||||
* @param out_quad_mode Pointer to store the output mode.
|
||||
* - SPI_FLASH_QOUT: QE is enabled
|
||||
* - otherwise: QE is disabled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - or other error passed from the ``common_command`` function of host driver
|
||||
*/
|
||||
esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_quad_mode);
|
||||
|
||||
/**
|
||||
* Generic SPI flash chip_drv, uses all the above functions for its operations.
|
||||
@@ -244,6 +258,78 @@ extern const spi_flash_chip_t esp_flash_chip_generic;
|
||||
*/
|
||||
esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms);
|
||||
|
||||
/// Function pointer type for reading status register with QE bit.
|
||||
typedef esp_err_t (*esp_flash_rdsr_func_t)(esp_flash_t* chip, uint32_t* out_sr);
|
||||
|
||||
/**
|
||||
* Use RDSR2 (35H) to read bit 15-8 of the SR, and RDSR (05H) to read bit 7-0.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param out_sr Pointer to buffer to hold the status register, 16 bits.
|
||||
*
|
||||
* @return ESP_OK if success, otherwise error code passed from the
|
||||
* `common_command` function of the host driver.
|
||||
*/
|
||||
esp_err_t spi_flash_common_read_status_16b_rdsr_rdsr2(esp_flash_t* chip, uint32_t* out_sr);
|
||||
|
||||
/**
|
||||
* Use RDSR2 (35H) to read bit 15-8 of the SR.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param out_sr Pointer to buffer to hold the status register, 8 bits.
|
||||
*
|
||||
* @return ESP_OK if success, otherwise error code passed from the
|
||||
* `common_command` function of the host driver.
|
||||
*/
|
||||
esp_err_t spi_flash_common_read_status_8b_rdsr2(esp_flash_t* chip, uint32_t* out_sr);
|
||||
|
||||
/**
|
||||
* Use RDSR (05H) to read bit 7-0 of the SR.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param out_sr Pointer to buffer to hold the status register, 8 bits.
|
||||
*
|
||||
* @return ESP_OK if success, otherwise error code passed from the
|
||||
* `common_command` function of the host driver.
|
||||
*/
|
||||
esp_err_t spi_flash_common_read_status_8b_rdsr(esp_flash_t* chip, uint32_t* out_sr);
|
||||
|
||||
/// Function pointer type for writing status register with QE bit.
|
||||
typedef esp_err_t (*esp_flash_wrsr_func_t)(esp_flash_t* chip, uint32_t sr);
|
||||
|
||||
/**
|
||||
* Use WRSR (01H) to write bit 7-0 of the SR.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param sr Value of the status register to write, 8 bits.
|
||||
*
|
||||
* @return ESP_OK if success, otherwise error code passed from the
|
||||
* `common_command` function of the host driver.
|
||||
*/
|
||||
esp_err_t spi_flash_common_write_status_8b_wrsr(esp_flash_t* chip, uint32_t sr);
|
||||
|
||||
/**
|
||||
* Use WRSR (01H) to write bit 15-0 of the SR.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param sr Value of the status register to write, 16 bits.
|
||||
*
|
||||
* @return ESP_OK if success, otherwise error code passed from the
|
||||
* `common_command` function of the host driver.
|
||||
*/
|
||||
esp_err_t spi_flash_common_write_status_16b_wrsr(esp_flash_t* chip, uint32_t sr);
|
||||
|
||||
/**
|
||||
* Use WRSR2 (31H) to write bit 15-8 of the SR.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param sr Value of the status register to write, 8 bits.
|
||||
*
|
||||
* @return ESP_OK if success, otherwise error code passed from the
|
||||
* `common_command` function of the host driver.
|
||||
*/
|
||||
esp_err_t spi_flash_common_write_status_8b_wrsr2(esp_flash_t* chip, uint32_t sr);
|
||||
|
||||
/**
|
||||
* @brief Utility function for set_read_mode chip_drv function. If required,
|
||||
* set and check the QE bit in the flash chip to enable the QIO/QOUT mode.
|
||||
@@ -253,16 +339,19 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_
|
||||
*
|
||||
* Registers to actually do Quad transtions and command to be sent in reading
|
||||
* should also be configured via
|
||||
* spi_flash_chip_generic_config_host_read_mode().
|
||||
* spi_flash_chip_generic_config_host_io_mode().
|
||||
*
|
||||
* @param qe_rdsr_command SPI flash command to read status register
|
||||
* @param qe_wrsr_command SPI flash command to write status register
|
||||
* @param qe_sr_bitwidth Width of the status register these commands operate on, in bits.
|
||||
* @param qe_sr_bit Bit mask for enabling Quad Enable functions on this chip.
|
||||
* Note that the bit length and qe position of wrsr_func, rdsr_func and
|
||||
* qe_sr_bit should be consistent.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use.
|
||||
* @param wrsr_func Function pointer for writing the status register
|
||||
* @param rdsr_func Function pointer for reading the status register
|
||||
* @param qe_sr_bit status with the qe bit only.
|
||||
*
|
||||
* @return always ESP_OK (currently).
|
||||
*/
|
||||
esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit);
|
||||
esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t wrsr_func, esp_flash_rdsr_func_t rdsr_func, uint32_t qe_sr_bit);
|
||||
|
||||
/**
|
||||
* @brief Configure the host registers to use the specified read mode set in
|
||||
@@ -278,17 +367,4 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm
|
||||
* - 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_read_mode(esp_flash_t *chip);
|
||||
|
||||
/**
|
||||
* @brief Returns true if chip is configured for Quad I/O or Quad Fast Read.
|
||||
*
|
||||
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
|
||||
*
|
||||
* @return true if flash works in quad mode, otherwise false
|
||||
*/
|
||||
static inline bool spi_flash_is_quad_mode(const esp_flash_t *chip)
|
||||
{
|
||||
return (chip->read_mode == SPI_FLASH_QIO) || (chip->read_mode == SPI_FLASH_QOUT);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip);
|
||||
|
@@ -144,7 +144,7 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
// Configure the host, and return
|
||||
spi_flash_chip_generic_config_host_read_mode(chip);
|
||||
spi_flash_chip_generic_config_host_io_mode(chip);
|
||||
|
||||
while (err == ESP_OK && length > 0) {
|
||||
uint32_t read_len = MIN(length, chip->host->max_read_bytes);
|
||||
@@ -277,7 +277,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_m
|
||||
return (timeout_ms > 0) ? ESP_OK : ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_generic_config_host_read_mode(esp_flash_t *chip)
|
||||
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip)
|
||||
{
|
||||
uint32_t dummy_cyclelen_base;
|
||||
uint32_t addr_bitlen;
|
||||
@@ -320,62 +320,33 @@ esp_err_t spi_flash_chip_generic_config_host_read_mode(esp_flash_t *chip)
|
||||
return ESP_ERR_FLASH_NOT_INITIALISED;
|
||||
}
|
||||
|
||||
return chip->host->configure_host_read_mode(chip->host, chip->read_mode, addr_bitlen, dummy_cyclelen_base, read_command);
|
||||
return chip->host->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base,
|
||||
chip->read_mode);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit)
|
||||
{
|
||||
if (spi_flash_is_quad_mode(chip)) {
|
||||
// Ensure quad modes are enabled, using the Quad Enable parameters supplied.
|
||||
spi_flash_trans_t t = {
|
||||
.command = qe_rdsr_command,
|
||||
.mosi_data = 0,
|
||||
.mosi_len = 0,
|
||||
.miso_len = qe_sr_bitwidth,
|
||||
};
|
||||
chip->host->common_command(chip->host, &t);
|
||||
unsigned sr = t.miso_data[0];
|
||||
ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr);
|
||||
if ((sr & qe_sr_bit) == 0) {
|
||||
//some chips needs the write protect to be disabled before writing to Status Register
|
||||
chip->chip_drv->set_chip_write_protect(chip, false);
|
||||
|
||||
sr |= qe_sr_bit;
|
||||
spi_flash_trans_t t = {
|
||||
.command = qe_wrsr_command,
|
||||
.mosi_data = sr,
|
||||
.mosi_len = qe_sr_bitwidth,
|
||||
.miso_len = 0,
|
||||
};
|
||||
chip->host->common_command(chip->host, &t);
|
||||
|
||||
/* Check the new QE bit has stayed set */
|
||||
spi_flash_trans_t t_rdsr = {
|
||||
.command = qe_rdsr_command,
|
||||
.mosi_data = 0,
|
||||
.mosi_len = 0,
|
||||
.miso_len = qe_sr_bitwidth
|
||||
};
|
||||
chip->host->common_command(chip->host, &t_rdsr);
|
||||
sr = t_rdsr.miso_data[0];
|
||||
ESP_EARLY_LOGV(TAG, "set_read_mode: status after 0x%x", sr);
|
||||
if ((sr & qe_sr_bit) == 0) {
|
||||
return ESP_ERR_FLASH_NO_RESPONSE;
|
||||
}
|
||||
|
||||
chip->chip_drv->set_chip_write_protect(chip, true);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_generic_set_read_mode(esp_flash_t *chip)
|
||||
esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
|
||||
{
|
||||
// On "generic" chips, this involves checking
|
||||
// bit 1 (QE) of RDSR2 (35h) result
|
||||
// (it works this way on GigaDevice & Fudan Micro chips, probably others...)
|
||||
const uint8_t BIT_QE = 1 << 1;
|
||||
return spi_flash_common_set_read_mode(chip, CMD_RDSR2, CMD_WRSR2, 8, BIT_QE);
|
||||
uint32_t sr;
|
||||
esp_err_t ret = spi_flash_common_read_status_8b_rdsr2(chip, &sr);
|
||||
if (ret == ESP_OK) {
|
||||
*out_io_mode = ((sr & BIT_QE)? SPI_FLASH_QOUT: 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_generic_set_io_mode(esp_flash_t *chip)
|
||||
{
|
||||
// On "generic" chips, this involves checking
|
||||
// bit 9 (QE) of RDSR (05h) result
|
||||
const uint32_t BIT_QE = 1 << 9;
|
||||
return spi_flash_common_set_io_mode(chip,
|
||||
spi_flash_common_write_status_16b_wrsr,
|
||||
spi_flash_common_read_status_16b_rdsr_rdsr2,
|
||||
BIT_QE);
|
||||
}
|
||||
|
||||
static const char chip_name[] = "generic";
|
||||
@@ -409,5 +380,134 @@ const spi_flash_chip_t esp_flash_chip_generic = {
|
||||
.write_encrypted = spi_flash_chip_generic_write_encrypted,
|
||||
|
||||
.wait_idle = spi_flash_chip_generic_wait_idle,
|
||||
.set_read_mode = spi_flash_chip_generic_set_read_mode,
|
||||
.set_io_mode = spi_flash_chip_generic_set_io_mode,
|
||||
.get_io_mode = spi_flash_chip_generic_get_io_mode,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Utility functions
|
||||
******************************************************************************/
|
||||
|
||||
static esp_err_t spi_flash_common_read_qe_sr(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_sr_bitwidth, uint32_t *sr)
|
||||
{
|
||||
spi_flash_trans_t t = {
|
||||
.command = qe_rdsr_command,
|
||||
.mosi_data = 0,
|
||||
.mosi_len = 0,
|
||||
.miso_len = qe_sr_bitwidth,
|
||||
};
|
||||
esp_err_t ret = chip->host->common_command(chip->host, &t);
|
||||
*sr = t.miso_data[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t spi_flash_common_write_qe_sr(esp_flash_t *chip, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, uint32_t qe)
|
||||
{
|
||||
spi_flash_trans_t t = {
|
||||
.command = qe_wrsr_command,
|
||||
.mosi_data = qe,
|
||||
.mosi_len = qe_sr_bitwidth,
|
||||
.miso_len = 0,
|
||||
};
|
||||
return chip->host->common_command(chip->host, &t);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_read_status_16b_rdsr_rdsr2(esp_flash_t* chip, uint32_t* out_sr)
|
||||
{
|
||||
uint32_t sr, sr2;
|
||||
esp_err_t ret = spi_flash_common_read_qe_sr(chip, CMD_RDSR2, 8, &sr2);
|
||||
if (ret == ESP_OK) {
|
||||
ret = spi_flash_common_read_qe_sr(chip, CMD_RDSR, 8, &sr);
|
||||
}
|
||||
if (ret == ESP_OK) {
|
||||
*out_sr = (sr & 0xff) | ((sr2 & 0xff) << 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_read_status_8b_rdsr2(esp_flash_t* chip, uint32_t* out_sr)
|
||||
{
|
||||
return spi_flash_common_read_qe_sr(chip, CMD_RDSR2, 8, out_sr);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_read_status_8b_rdsr(esp_flash_t* chip, uint32_t* out_sr)
|
||||
{
|
||||
return spi_flash_common_read_qe_sr(chip, CMD_RDSR, 8, out_sr);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_write_status_16b_wrsr(esp_flash_t* chip, uint32_t sr)
|
||||
{
|
||||
return spi_flash_common_write_qe_sr(chip, CMD_WRSR, 16, sr);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_write_status_8b_wrsr(esp_flash_t* chip, uint32_t sr)
|
||||
{
|
||||
return spi_flash_common_write_qe_sr(chip, CMD_WRSR, 8, sr);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_write_status_8b_wrsr2(esp_flash_t* chip, uint32_t sr)
|
||||
{
|
||||
return spi_flash_common_write_qe_sr(chip, CMD_WRSR2, 8, sr);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t wrsr_func, esp_flash_rdsr_func_t rdsr_func, uint32_t qe_sr_bit)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
const bool is_quad_mode = esp_flash_is_quad_mode(chip);
|
||||
bool update_config = false;
|
||||
const bool force_check = true; //in case some chips doesn't support erase QE
|
||||
|
||||
bool need_check = is_quad_mode;
|
||||
if (force_check) {
|
||||
need_check = true;
|
||||
}
|
||||
|
||||
uint32_t sr_update;
|
||||
if (need_check) {
|
||||
// Ensure quad modes are enabled, using the Quad Enable parameters supplied.
|
||||
uint32_t sr;
|
||||
ret = (*rdsr_func)(chip, &sr);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
ESP_EARLY_LOGD(TAG, "set_io_mode: status before 0x%x", sr);
|
||||
if (is_quad_mode) {
|
||||
sr_update = sr | qe_sr_bit;
|
||||
} else {
|
||||
sr_update = sr & (~qe_sr_bit);
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "set_io_mode: status update 0x%x", sr_update);
|
||||
if (sr != sr_update) {
|
||||
update_config = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_config) {
|
||||
//some chips needs the write protect to be disabled before writing to Status Register
|
||||
chip->chip_drv->set_chip_write_protect(chip, false);
|
||||
|
||||
ret = (*wrsr_func)(chip, sr_update);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check the new QE bit has stayed set */
|
||||
uint32_t sr;
|
||||
ret = (*rdsr_func)(chip, &sr);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
ESP_EARLY_LOGD(TAG, "set_io_mode: status after 0x%x", sr);
|
||||
if (sr != sr_update) {
|
||||
ret = ESP_ERR_FLASH_NO_RESPONSE;
|
||||
}
|
||||
|
||||
chip->chip_drv->set_chip_write_protect(chip, true);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@@ -35,13 +35,29 @@ esp_err_t spi_flash_chip_issi_probe(esp_flash_t *chip, uint32_t flash_id)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_issi_set_read_mode(esp_flash_t *chip)
|
||||
esp_err_t spi_flash_chip_issi_set_io_mode(esp_flash_t *chip)
|
||||
{
|
||||
/* ISSI uses bit 6 of "basic" SR as Quad Enable */
|
||||
const uint8_t BIT_QE = 1 << 6;
|
||||
return spi_flash_common_set_read_mode(chip, CMD_RDSR, CMD_WRSR, 8, BIT_QE);
|
||||
return spi_flash_common_set_io_mode(chip,
|
||||
spi_flash_common_write_status_8b_wrsr,
|
||||
spi_flash_common_read_status_8b_rdsr,
|
||||
BIT_QE);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
|
||||
{
|
||||
/* ISSI uses bit 6 of "basic" SR as Quad Enable */
|
||||
const uint8_t BIT_QE = 1 << 6;
|
||||
uint32_t sr;
|
||||
esp_err_t ret = spi_flash_common_read_status_8b_rdsr(chip, &sr);
|
||||
if (ret == ESP_OK) {
|
||||
*out_io_mode = ((sr & BIT_QE)? SPI_FLASH_QOUT: 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const char chip_name[] = "issi";
|
||||
|
||||
// The issi chip can use the functions for generic chips except from set read mode and probe,
|
||||
@@ -73,5 +89,6 @@ const spi_flash_chip_t esp_flash_chip_issi = {
|
||||
.write_encrypted = spi_flash_chip_generic_write_encrypted,
|
||||
|
||||
.wait_idle = spi_flash_chip_generic_wait_idle,
|
||||
.set_read_mode = spi_flash_chip_issi_set_read_mode,
|
||||
.set_io_mode = spi_flash_chip_issi_set_io_mode,
|
||||
.get_io_mode = spi_flash_chip_issi_get_io_mode,
|
||||
};
|
||||
|
@@ -128,7 +128,7 @@ static void release_bus(int host_id)
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t speed)
|
||||
static void setup_new_chip(esp_flash_io_mode_t io_mode, esp_flash_speed_t speed)
|
||||
{
|
||||
//the bus should be initialized before the flash is attached to the bus
|
||||
setup_bus(TEST_HOST);
|
||||
|
Reference in New Issue
Block a user