return dev->ext2.st != 0;
}
-/**
- * Set phases for user-defined transaction to read
- *
- * @param dev Beginning address of the peripheral registers.
- */
-static inline void spi_flash_ll_read_phase(spi_dev_t *dev)
-{
- typeof (dev->user) user = {
- .usr_command = 1,
- .usr_mosi = 0,
- .usr_miso = 1,
- .usr_addr = 1,
- };
- dev->user = user;
-}
/*------------------------------------------------------------------------------
* Configs
*----------------------------------------------------------------------------*/
* @param dev Beginning address of the peripheral registers.
* @param read_mode I/O mode to use in the following transactions.
*/
-static inline void spi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_read_mode_t read_mode)
+static inline void spi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
ctrl.val &= ~(SPI_FREAD_QIO_M | SPI_FREAD_QUAD_M | SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M);
bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver);
/**
- * Configure the SPI host hardware registers for the specified read mode.
+ * @brief Configure the SPI host hardware registers for the specified io mode.
*
* Note that calling this configures SPI host registers, so if running any
- * other commands as part of set_read_mode() then these must be run before
+ * other commands as part of set_io_mode() then these must be run before
* calling this function.
*
+ * The command value, address length and dummy cycles are configured according
+ * to the format of read commands:
+ *
+ * - command: 8 bits, value set.
+ * - address: 24 bits
+ * - dummy: cycles to compensate the input delay
+ * - out & in data: 0 bits.
+ *
+ * The following commands still need to:
+ *
+ * - Read data: set address value and data (length and contents), no need
+ * to touch command and dummy phases.
+ * - Common read: set command value, address value (or length to 0 if not used)
+ * - Common write: set command value, address value (or length to 0 if not
+ * used), disable dummy phase, and set output data.
+ *
* @param driver The driver context
- * @param read_mode The HW read mode to use
+ * @param io_mode The HW read mode to use
* @param addr_bitlen Length of the address phase, in bits
* @param dummy_cyclelen_base Base cycles of the dummy phase, some extra dummy cycles may be appended to compensate the timing.
- * @param read_command Actual reading command to send to flash chip on the bus.
+ * @param command Actual reading command to send to flash chip on the bus.
*
* @return always return ESP_OK.
*/
-esp_err_t spi_flash_hal_configure_host_read_mode(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode,
- uint32_t addr_bitlen, uint32_t dummy_cyclelen_base,
- uint32_t read_command);
+esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_driver_t *driver, uint32_t command, uint32_t addr_bitlen,
+ int dummy_cyclelen_base, esp_flash_io_mode_t io_mode);
/**
* Poll until the last operation is done.
SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
-} esp_flash_read_mode_t;
+} esp_flash_io_mode_t;
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
*/
bool (*host_idle)(spi_flash_host_driver_t *driver);
/**
- * Configure the host to work at different read mode.
+ * Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
- esp_err_t (*configure_host_read_mode)(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode, uint32_t addr_bitlen, uint32_t dummy_bitlen_base, uint32_t read_command);
+ esp_err_t (*configure_host_io_mode)(spi_flash_host_driver_t *driver, uint32_t command,
+ uint32_t addr_bitlen, int dummy_bitlen_base,
+ esp_flash_io_mode_t io_mode);
/**
* Internal use, poll the HW until the last operation is done.
*/
ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy);
return ESP_OK;
}
-
-static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *chip_drv)
-{
- return ((spi_flash_memspi_data_t *)chip_drv->driver_data)->spi;
-}
return ESP_OK;
}
-esp_err_t spi_flash_hal_configure_host_read_mode(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode,
- uint32_t addr_bitlen, uint32_t dummy_cyclelen_base,
- uint32_t read_command)
+esp_err_t spi_flash_hal_configure_host_io_mode(
+ spi_flash_host_driver_t *host,
+ uint32_t command,
+ uint32_t addr_bitlen,
+ int dummy_cyclelen_base,
+ esp_flash_io_mode_t io_mode)
{
// Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary...
int dummy_cyclelen = dummy_cyclelen_base + ((spi_flash_memspi_data_t *)driver->driver_data)->extra_dummy;
spi_dev_t *dev = get_spi_dev(driver);
+ spi_flash_ll_set_command8(dev, command);
spi_flash_ll_set_addr_bitlen(dev, addr_bitlen);
- spi_flash_ll_set_command8(dev, read_command);
- spi_flash_ll_read_phase(dev);
spi_flash_ll_set_dummy(dev, dummy_cyclelen);
- spi_flash_ll_set_read_mode(dev, read_mode);
+ //disable all data phases, enable them later if needed
+ spi_flash_ll_set_miso_bitlen(dev, 0);
+ spi_flash_ll_set_mosi_bitlen(dev, 0);
+ spi_flash_ll_set_read_mode(dev, io_mode);
return ESP_OK;
}
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *chip_drv, spi_flash_trans_t *trans)
{
- chip_drv->configure_host_read_mode(chip_drv, SPI_FLASH_FASTRD, 0, 0, 0);
+ host->configure_host_io_mode(host, trans->command, 0, 0, SPI_FLASH_FASTRD);
+
spi_dev_t *dev = get_spi_dev(chip_drv);
- spi_flash_ll_set_command8(dev, trans->command);
- spi_flash_ll_set_addr_bitlen(dev, 0);
+ //disable dummy if no input phase
+ if (trans->miso_len == 0) {
+ spi_flash_ll_set_dummy(dev, 0);
+ }
+
spi_flash_ll_set_miso_bitlen(dev, trans->miso_len);
spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len);
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len)
{
spi_dev_t *dev = get_spi_dev(chip_drv);
- //the command is already set by ``spi_flash_hal_configure_host_read_mode`` before.
+ //the command is already set by ``spi_flash_hal_configure_host_io_mode`` before.
spi_flash_ll_set_address(dev, address << 8);
spi_flash_ll_set_miso_bitlen(dev, read_len * 8);
spi_flash_ll_user_start(dev);
# 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()
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")
"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.
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;
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)
{
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
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.
};
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
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;
.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, \
}
*
* 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
* - 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.
*/
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.
*
* 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
* - 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);
{
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);
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;
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)
+esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
{
- 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);
- }
+ // 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;
+ 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 ESP_OK;
+ return ret;
}
-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)
{
// 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);
+ // 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";
.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;
+}
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,
.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,
};
}
}
-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);