Merge branch 'feat/esp_flash_data_slicer' into 'master'

esp_flash: refactor to be compatible with the latest ROM

Closes IDF-1664 and IDFGH-2074

See merge request espressif/esp-idf!8565
This commit is contained in:
Michael (XIAO Xufeng) 2020-07-16 16:07:32 +08:00
commit 79a5b0b5af
20 changed files with 600 additions and 383 deletions

View File

@ -37,11 +37,13 @@
* implementations that also use the SPI peripheral.
*/
typedef struct {
spi_flash_host_inst_t inst; ///< Host instance, containing host data and function pointer table. May update with the host (hardware version).
spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation.
int cs_num; ///< Which cs pin is used, 0-2.
int extra_dummy;
spi_flash_ll_clock_reg_t clock_conf;
} spi_flash_memspi_data_t;
int extra_dummy; ///< Pre-calculated extra dummy used for compensation
spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value
uint32_t reserved_config[2]; ///< The ROM has reserved some memory for configurations with one set of driver code. (e.g. QPI mode, 64-bit address mode, etc.)
} spi_flash_hal_context_t;
/// Configuration structure for the SPI driver.
typedef struct {
@ -50,7 +52,7 @@ typedef struct {
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.
} spi_flash_memspi_config_t;
} spi_flash_hal_config_t;
/**
* Configure SPI flash hal settings.
@ -62,16 +64,16 @@ typedef struct {
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: the data buffer is not in the DRAM.
*/
esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg);
esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_hal_config_t *cfg);
/**
* Configure the device-related register before transactions.
*
* @param driver The driver context.
* @param host The driver context.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver);
esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host);
/**
* Send an user-defined spi transaction to the device.
@ -80,60 +82,60 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver);
* particular commands. Since this function supports timing compensation, it is
* also used to receive some data when the frequency is high.
*
* @param driver The driver context.
* @param host The driver context.
* @param trans The transaction to send, also holds the received data.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans);
esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans);
/**
* Erase whole flash chip by using the erase chip (C7h) command.
*
* @param driver The driver context.
* @param host The driver context.
*/
void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver);
void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address through the sector erase (20h)
* command.
*
* @param driver The driver context.
* @param host The driver context.
* @param start_address Start address of the sector to erase.
*/
void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address);
void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a specific 64KB block by its start address through the 64KB block
* erase (D8h) command.
*
* @param driver The driver context.
* @param host The driver context.
* @param start_address Start address of the block to erase.
*/
void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address);
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Program a page of the flash using the page program (02h) command.
*
* @param driver The driver context.
* @param host The driver context.
* @param address Address of the page to program
* @param buffer Data to program
* @param length Size of the buffer in bytes, no larger than ``SPI_FLASH_HAL_MAX_WRITE_BYTES`` (64) bytes.
*/
void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length);
void spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/**
* Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to
* configure the read command before calling this function.
*
* @param driver The driver context.
* @param host The driver context.
* @param buffer Buffer to store the read data
* @param address Address to read
* @param length Length to read, no larger than ``SPI_FLASH_HAL_MAX_READ_BYTES`` (64) bytes.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len);
esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/**
* @brief Send the write enable (06h) or write disable (04h) command to the flash chip.
@ -143,16 +145,16 @@ esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp);
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp);
/**
* Check whether the SPI host is idle and can perform other operations.
*
* @param driver The driver context.
* @param host The driver context.
*
* @return ture if idle, otherwise false.
*/
bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver);
bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host);
/**
* @brief Configure the SPI host hardware registers for the specified io mode.
@ -177,7 +179,7 @@ bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver);
* - 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 host The driver context
* @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.
@ -185,34 +187,34 @@ bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver);
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_driver_t *driver, uint32_t command, uint32_t addr_bitlen,
esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_inst_t *host, 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.
*
* @param driver The driver context.
* @param host The driver context.
*/
void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *driver);
void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host);
/**
* Check whether the given buffer can be used as the write buffer directly. If 'chip' is connected to the main SPI bus, we can only write directly from
* regions that are accessible ith cache disabled. *
*
* @param driver The driver context
* @param host The driver context
* @param p The buffer holding data to send.
*
* @return True if the buffer can be used to send data, otherwise false.
*/
bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *driver, const void *p);
bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p);
/**
* Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from
* regions that are accessible ith cache disabled. *
*
* @param driver The driver context
* @param host The driver context
* @param p The buffer to hold the received data.
*
* @return True if the buffer can be used to receive data, otherwise false.
*/
bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p);
bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p);

View File

@ -68,84 +68,105 @@ typedef enum {
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
struct spi_flash_host_driver_t;
typedef struct spi_flash_host_driver_t spi_flash_host_driver_t;
struct spi_flash_host_driver_s;
typedef struct spi_flash_host_driver_s spi_flash_host_driver_t;
/** SPI Flash Host driver instance */
typedef struct {
const struct spi_flash_host_driver_s* driver; ///< Pointer to the implementation function table
// Implementations can wrap this structure into their own ones, and append other data here
} spi_flash_host_inst_t ;
/** Host driver configuration and context structure. */
struct spi_flash_host_driver_t {
/**
* Configuration and static data used by the specific host driver. The type
* is determined by the host driver.
*/
void *driver_data;
struct spi_flash_host_driver_s {
/**
* Configure the device-related register before transactions. This saves
* some time to re-configure those registers when we send continuously
*/
esp_err_t (*dev_config)(spi_flash_host_driver_t *driver);
esp_err_t (*dev_config)(spi_flash_host_inst_t *host);
/**
* Send an user-defined spi transaction to the device.
*/
esp_err_t (*common_command)(spi_flash_host_driver_t *driver, spi_flash_trans_t *t);
esp_err_t (*common_command)(spi_flash_host_inst_t *host, spi_flash_trans_t *t);
/**
* Read flash ID.
*/
esp_err_t (*read_id)(spi_flash_host_driver_t *driver, uint32_t *id);
esp_err_t (*read_id)(spi_flash_host_inst_t *host, uint32_t *id);
/**
* Erase whole flash chip.
*/
void (*erase_chip)(spi_flash_host_driver_t *driver);
void (*erase_chip)(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address.
*/
void (*erase_sector)(spi_flash_host_driver_t *driver, uint32_t start_address);
void (*erase_sector)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a specific block by its start address.
*/
void (*erase_block)(spi_flash_host_driver_t *driver, uint32_t start_address);
void (*erase_block)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Read the status of the flash chip.
*/
esp_err_t (*read_status)(spi_flash_host_driver_t *driver, uint8_t *out_sr);
esp_err_t (*read_status)(spi_flash_host_inst_t *host, uint8_t *out_sr);
/**
* Disable write protection.
*/
esp_err_t (*set_write_protect)(spi_flash_host_driver_t *driver, bool wp);
esp_err_t (*set_write_protect)(spi_flash_host_inst_t *host, bool wp);
/**
* Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length.
*/
void (*program_page)(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length);
/** Check whether need to allocate new buffer to write */
bool (*supports_direct_write)(spi_flash_host_driver_t *driver, const void *p);
/** Check whether need to allocate new buffer to read */
bool (*supports_direct_read)(spi_flash_host_driver_t *driver, const void *p);
/** maximum length of program_page */
int max_write_bytes;
void (*program_page)(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/** Check whether given buffer can be directly used to write */
bool (*supports_direct_write)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for write data. The `program_page` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to write
* @param len Length request to write
* @param align_addr Output of the aligned address to write to
* @param page_size Physical page size of the flash chip
* @return Length that can be actually written in one `program_page` call
*/
int (*write_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr,
uint32_t page_size);
/**
* Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length.
*/
esp_err_t (*read)(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len);
/** maximum length of read */
int max_read_bytes;
esp_err_t (*read)(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** Check whether given buffer can be directly used to read */
bool (*supports_direct_read)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for read data. The `read` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to read
* @param len Length request to read
* @param align_addr Output of the aligned address to read
* @param page_size Physical page size of the flash chip
* @return Length that can be actually read in one `read` call
*/
int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check whether the host is idle to perform new operations.
*/
bool (*host_idle)(spi_flash_host_driver_t *driver);
bool (*host_idle)(spi_flash_host_inst_t *host);
/**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
esp_err_t (*configure_host_io_mode)(spi_flash_host_driver_t *driver, uint32_t command,
esp_err_t (*configure_host_io_mode)(spi_flash_host_inst_t *host, 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.
*/
void (*poll_cmd_done)(spi_flash_host_driver_t *driver);
void (*poll_cmd_done)(spi_flash_host_inst_t *host);
/**
* For some host (SPI1), they are shared with a cache. When the data is
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size);
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
};
#ifdef __cplusplus

View File

@ -63,7 +63,7 @@ static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk
return apb_period_n / apbclk_n;
}
esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg)
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)) {
return ESP_ERR_INVALID_ARG;
@ -77,7 +77,8 @@ esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_
}
#endif
*data_out = (spi_flash_memspi_data_t) {
*data_out = (spi_flash_hal_context_t) {
.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, clock_cfg.freq),
@ -88,18 +89,18 @@ esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_
return ESP_OK;
}
bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *host, const void *p)
bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{
bool direct_write = ( ((spi_flash_memspi_data_t *)host->driver_data)->spi != spi_flash_ll_get_hw(SPI_HOST)
bool direct_write = ( ((spi_flash_hal_context_t *)host)->spi != spi_flash_ll_get_hw(SPI_HOST)
|| esp_ptr_in_dram(p) );
return direct_write;
}
bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *host, const void *p)
bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{
//currently the host doesn't support to read through dma, no word-aligned requirements
bool direct_read = ( ((spi_flash_memspi_data_t *)host->driver_data)->spi != spi_flash_ll_get_hw(SPI_HOST)
bool direct_read = ( ((spi_flash_hal_context_t *)host)->spi != spi_flash_ll_get_hw(SPI_HOST)
|| esp_ptr_in_dram(p) );
return direct_read;
}

View File

@ -19,32 +19,31 @@
#include "sdkconfig.h"
#define ADDRESS_MASK_24BIT 0xFFFFFF
#define COMPUTE_DUMMY_CYCLELEN(host, base) ((base) + ((spi_flash_memspi_data_t *)(host)->driver_data)->extra_dummy)
#define COMPUTE_DUMMY_CYCLELEN(host, base) ((base) + ((spi_flash_hal_context_t*)host)->extra_dummy)
static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *host)
static inline spi_dev_t *get_spi_dev(spi_flash_host_inst_t *host)
{
return ((spi_flash_memspi_data_t *)host->driver_data)->spi;
return ((spi_flash_hal_context_t*)host)->spi;
}
void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *host)
void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host)
{
while (!spi_flash_ll_cmd_is_done(get_spi_dev(host))) {
//nop
}
}
esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *host)
esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host)
{
spi_flash_memspi_data_t *drv_data = (spi_flash_memspi_data_t *)host->driver_data;
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_reset(dev);
spi_flash_ll_set_cs_pin(dev, drv_data->cs_num);
spi_flash_ll_set_clock(dev, &drv_data->clock_conf);
spi_flash_ll_set_cs_pin(dev, ((spi_flash_hal_context_t*)host)->cs_num);
spi_flash_ll_set_clock(dev, &((spi_flash_hal_context_t*)host)->clock_conf);
return ESP_OK;
}
esp_err_t spi_flash_hal_configure_host_io_mode(
spi_flash_host_driver_t *host,
spi_flash_host_inst_t *host,
uint32_t command,
uint32_t addr_bitlen,
int dummy_cyclelen_base,
@ -89,9 +88,9 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
return ESP_OK;
}
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *host, spi_flash_trans_t *trans)
esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans)
{
host->configure_host_io_mode(host, trans->command, trans->address_bitlen, 0, SPI_FLASH_FASTRD);
host->driver->configure_host_io_mode(host, trans->command, trans->address_bitlen, 0, SPI_FLASH_FASTRD);
spi_dev_t *dev = get_spi_dev(host);
@ -106,19 +105,19 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *host, spi_flash_
spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8);
spi_flash_ll_user_start(dev);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
spi_flash_ll_get_buffer_data(dev, trans->miso_data, trans->miso_len);
return ESP_OK;
}
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *host, void *buffer, uint32_t address, uint32_t read_len)
esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
{
spi_dev_t *dev = get_spi_dev(host);
int bitlen = spi_flash_ll_get_addr_bitlen(dev);
spi_flash_ll_set_usr_address(dev, address << (bitlen - 24), bitlen);
spi_flash_ll_set_miso_bitlen(dev, read_len * 8);
spi_flash_ll_user_start(dev);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
spi_flash_ll_get_buffer_data(dev, buffer, read_len);
return ESP_OK;
}

View File

@ -22,18 +22,18 @@
#include "spi_flash_hal_common.inc"
bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *host, const void *p)
bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_inst_t *host, const void *p)
{
return true;
}
bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *host, const void *p)
bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_inst_t *host, const void *p)
{
return true;
}
bool spi_flash_hal_gpspi_host_idle(spi_flash_host_driver_t *chip_drv)
bool spi_flash_hal_gpspi_host_idle(spi_flash_host_inst_t *host)
{
spi_dev_t *dev = get_spi_dev(chip_drv);
spi_dev_t *dev = get_spi_dev(host);
return spi_flash_ll_host_idle(dev);
}

View File

@ -14,51 +14,51 @@
#include "spi_flash_hal_common.inc"
void spi_flash_hal_erase_chip(spi_flash_host_driver_t *host)
void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
{
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_erase_chip(dev);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
}
void spi_flash_hal_erase_sector(spi_flash_host_driver_t *host, uint32_t start_address)
void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT);
spi_flash_ll_erase_sector(dev);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
}
void spi_flash_hal_erase_block(spi_flash_host_driver_t *host, uint32_t start_address)
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT);
spi_flash_ll_erase_block(dev);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
}
void spi_flash_hal_program_page(spi_flash_host_driver_t *host, const void *buffer, uint32_t address, uint32_t length)
void spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, (address & ADDRESS_MASK_24BIT) | (length << 24));
spi_flash_ll_program_page(dev, buffer, length);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
}
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *host, bool wp)
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp)
{
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_set_write_protect(dev, wp);
host->poll_cmd_done(host);
host->driver->poll_cmd_done(host);
return ESP_OK;
}
bool spi_flash_hal_host_idle(spi_flash_host_driver_t *chip_drv)
bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host)
{
spi_dev_t *dev = get_spi_dev(chip_drv);
spi_dev_t *dev = get_spi_dev(host);
bool idle = spi_flash_ll_host_idle(dev);
// Not clear if this is necessary, or only necessary if

View File

@ -71,12 +71,31 @@ _Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the i
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
static esp_err_t spiflash_start_default(esp_flash_t *chip);
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
typedef struct {
esp_err_t (*start)(esp_flash_t *chip);
esp_err_t (*end)(esp_flash_t *chip, esp_err_t err);
esp_err_t (*chip_check)(esp_flash_t **inout_chip);
} rom_spiflash_api_func_t;
// These functions can be placed in the ROM. For now we use the code in IDF.
DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
.start = spiflash_start_default,
.end = spiflash_end_default,
.chip_check = check_chip_pointer_default,
};
DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api;
/* Static function to notify OS of a new SPI flash operation.
If returns an error result, caller must abort. If returns ESP_OK, caller must
call spiflash_end() before returning.
call rom_spiflash_api_funcs->end() before returning.
*/
static esp_err_t IRAM_ATTR spiflash_start(esp_flash_t *chip)
static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip)
{
if (chip->os_func != NULL && chip->os_func->start != NULL) {
esp_err_t err = chip->os_func->start(chip->os_func_data);
@ -84,13 +103,13 @@ static esp_err_t IRAM_ATTR spiflash_start(esp_flash_t *chip)
return err;
}
}
chip->host->dev_config(chip->host);
chip->host->driver->dev_config(chip->host);
return ESP_OK;
}
/* Static function to notify OS that SPI flash operation is complete.
*/
static esp_err_t IRAM_ATTR spiflash_end(const esp_flash_t *chip, esp_err_t err)
static esp_err_t IRAM_ATTR spiflash_end_default(esp_flash_t *chip, esp_err_t err)
{
if (chip->os_func != NULL
&& chip->os_func->end != NULL) {
@ -102,6 +121,20 @@ static esp_err_t IRAM_ATTR spiflash_end(const esp_flash_t *chip, esp_err_t err)
return err;
}
// check that the 'chip' parameter is properly initialised
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip)
{
esp_flash_t *chip = *inout_chip;
if (chip == NULL) {
chip = esp_flash_default_chip;
}
*inout_chip = chip;
if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) {
return ESP_ERR_FLASH_NOT_INITIALISED;
}
return ESP_OK;
}
/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);
@ -118,8 +151,8 @@ bool esp_flash_chip_driver_initialized(const esp_flash_t *chip)
esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
{
esp_err_t err = ESP_OK;
if (chip == NULL || chip->host == NULL || chip->host->driver_data == NULL ||
((memspi_host_data_t*)chip->host->driver_data)->spi == NULL) {
if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_inst_t*)chip->host)->spi == NULL) {
return ESP_ERR_INVALID_ARG;
}
@ -152,7 +185,7 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
}
ESP_LOGI(TAG, "flash io: %s", io_mode_str[chip->read_mode]);
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -166,30 +199,30 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
}
}
// Done: all fields on 'chip' are initialised
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->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);
esp_err_t err = rom_spiflash_api_funcs->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);
err = chip->host->driver->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);
err = chip->host->driver->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);
return rom_spiflash_api_funcs->end(chip, err);
}
static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
@ -205,7 +238,7 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
// and also so esp_flash_registered_flash_drivers can live in flash
ESP_LOGD(TAG, "trying chip: %s", chip->chip_drv->name);
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -216,7 +249,7 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
// if probe succeeded, chip->drv stays set
drivers++;
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
if (err != ESP_OK) {
return err;
}
@ -228,16 +261,12 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
return ESP_OK;
}
// Convenience macro for beginning of all API functions,
// check that the 'chip' parameter is properly initialised
// and supports the operation in question
#define VERIFY_OP(OP) do { \
if (chip == NULL) { \
chip = esp_flash_default_chip; \
} \
if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) { \
return ESP_ERR_FLASH_NOT_INITIALISED; \
} \
/* Convenience macro for beginning of all API functions.
* Check the return value of `rom_spiflash_api_funcs->chip_check` is correct,
* and the chip supports the operation in question.
*/
#define VERIFY_CHIP_OP(OP) do { \
if (err != ESP_OK) return err; \
if (chip->chip_drv->OP == NULL) { \
return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \
} \
@ -245,28 +274,25 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id)
{
if (chip == NULL) {
chip = esp_flash_default_chip;
}
if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) {
return ESP_ERR_FLASH_NOT_INITIALISED;
}
if (out_id == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = spiflash_start(chip);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
//Accept uninitialized chip when reading chip id
if (err != ESP_OK && !(err == ESP_ERR_FLASH_NOT_INITIALISED && chip != NULL)) return err;
if (out_id == NULL) return ESP_ERR_INVALID_ARG;
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->host->read_id(chip->host, out_id);
err = chip->host->driver->read_id(chip->host, out_id);
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{
VERIFY_OP(detect_size);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(detect_size);
if (out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
@ -275,7 +301,7 @@ esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
return ESP_OK;
}
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -284,28 +310,31 @@ esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
if (err == ESP_OK) {
chip->size = detect_size;
}
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
{
VERIFY_OP(erase_chip);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(erase_chip);
CHECK_WRITE_ADDRESS(chip, 0, chip->size);
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->erase_chip(chip);
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len)
{
VERIFY_OP(erase_sector);
VERIFY_OP(erase_block);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(erase_sector);
VERIFY_CHIP_OP(erase_block);
CHECK_WRITE_ADDRESS(chip, start, len);
uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size;
uint32_t sector_size = chip->chip_drv->sector_size;
@ -320,12 +349,12 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = ESP_OK;
err = ESP_OK;
// Check for write protected regions overlapping the erase region
if (chip->chip_drv->get_protected_regions != NULL &&
chip->chip_drv->num_protectable_regions > 0) {
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -341,7 +370,7 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
}
}
// Don't lock the SPI flash for the entire erase, as this may be very long
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
}
#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE
@ -351,7 +380,7 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE
int64_t start_time_us = esp_timer_get_time();
#endif
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -371,7 +400,7 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
len -= sector_size;
}
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE
no_yield_time_us += (esp_timer_get_time() - start_time_us);
@ -388,34 +417,36 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *out_write_protected)
{
VERIFY_OP(get_chip_write_protect);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_chip_write_protect);
if (out_write_protected == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->get_chip_write_protect(chip, out_write_protected);
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect)
{
VERIFY_OP(set_chip_write_protect);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_chip_write_protect);
//TODO: skip writing if already locked or unlocked
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->set_chip_write_protect(chip, write_protect);
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **out_regions, uint32_t *out_num_regions)
@ -423,7 +454,8 @@ esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_f
if(out_num_regions != NULL) {
*out_num_regions = 0; // In case caller doesn't check result
}
VERIFY_OP(get_protected_regions);
esp_err_t err = rom_spiflash_api_funcs->chip_check((esp_flash_t **)&chip);
VERIFY_CHIP_OP(get_protected_regions);
if(out_regions == NULL || out_num_regions == NULL) {
return ESP_ERR_INVALID_ARG;
@ -452,20 +484,21 @@ static esp_err_t find_region(const esp_flash_t *chip, const esp_flash_region_t *
esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *out_protected)
{
VERIFY_OP(get_protected_regions);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_protected_regions);
if (out_protected == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t index;
esp_err_t err = find_region(chip, region, &index);
err = find_region(chip, region, &index);
if (err != ESP_OK) {
return err;
}
uint64_t protection_mask = 0;
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -475,21 +508,22 @@ esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_
*out_protected = protection_mask & (1LL << index);
}
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protect)
{
VERIFY_OP(set_protected_regions);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_protected_regions);
uint8_t index;
esp_err_t err = find_region(chip, region, &index);
err = find_region(chip, region, &index);
if (err != ESP_OK) {
return err;
}
uint64_t protection_mask = 0;
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -504,7 +538,7 @@ esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_
err = chip->chip_drv->set_protected_regions(chip, protection_mask);
}
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
@ -512,13 +546,14 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
if (length == 0) {
return ESP_OK;
}
VERIFY_OP(read);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(read);
if (buffer == NULL || address > chip->size || address+length > chip->size) {
return ESP_ERR_INVALID_ARG;
}
//when the cache is disabled, only the DRAM can be read, check whether we need to receive in another buffer in DRAM.
bool direct_read = chip->host->supports_direct_read(chip->host, buffer);
bool direct_read = chip->host->driver->supports_direct_read(chip->host, buffer);
uint8_t* temp_buffer = NULL;
//each time, we at most read this length
@ -526,29 +561,17 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
size_t read_chunk_size = MIN(MAX_READ_CHUNK, length);
if (!direct_read) {
/* Allocate temporary internal buffer to use for the actual read. If the preferred size
doesn't fit in free internal memory, allocate the largest available free block.
(May need to shrink read_chunk_size and retry due to race conditions with other tasks
also allocating from the heap.)
*/
unsigned retries = 5;
while(temp_buffer == NULL && retries--) {
read_chunk_size = MIN(read_chunk_size, heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
read_chunk_size = (read_chunk_size + 3) & ~3;
temp_buffer = heap_caps_malloc(read_chunk_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}
ESP_LOGV(TAG, "allocate temp buffer: %p (%d)", temp_buffer, read_chunk_size);
size_t actual_len = 0;
temp_buffer = chip->os_func->get_temp_buffer(chip->os_func_data, read_chunk_size, &actual_len);
read_chunk_size = actual_len;
if (temp_buffer == NULL) {
return ESP_ERR_NO_MEM;
}
}
esp_err_t err = ESP_OK;
err = ESP_OK;
do {
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
break;
}
@ -562,11 +585,11 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read);
}
if (err != ESP_OK) {
spiflash_end(chip, err);
rom_spiflash_api_funcs->end(chip, err);
break;
}
//even if this is failed, the data is still valid, copy before quit
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
//copy back to the original buffer
if (temp_buffer) {
@ -574,10 +597,10 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
}
address += length_to_read;
length -= length_to_read;
buffer += length_to_read;
buffer = (void*)((intptr_t)buffer + length_to_read);
} while (err == ESP_OK && length > 0);
free(temp_buffer);
chip->os_func->release_temp_buffer(chip->os_func_data, temp_buffer);
return err;
}
@ -586,16 +609,17 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
if (length == 0) {
return ESP_OK;
}
VERIFY_OP(write);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(write);
CHECK_WRITE_ADDRESS(chip, address, length);
if (buffer == NULL || address > chip->size || address+length > chip->size) {
return ESP_ERR_INVALID_ARG;
}
//when the cache is disabled, only the DRAM can be read, check whether we need to copy the data first
bool direct_write = chip->host->supports_direct_write(chip->host, buffer);
bool direct_write = chip->host->driver->supports_direct_write(chip->host, buffer);
esp_err_t err = ESP_OK;
err = ESP_OK;
/* Write output in chunks, either by buffering on stack or
by artificially cutting into MAX_WRITE_CHUNK parts (in an OS
environment, this prevents writing from causing interrupt or higher priority task
@ -613,7 +637,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
write_buf = buf;
}
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -624,7 +648,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
buffer = (void *)((intptr_t)buffer + write_len);
length -= write_len;
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
} while (err == ESP_OK && length > 0);
return err;
}
@ -639,11 +663,8 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres
* is no way to support non-standard chips. We use the legacy
* implementation and skip the chip and driver layers.
*/
if (chip == NULL) {
chip = esp_flash_default_chip;
} else if (chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) return err;
if (buffer == NULL || address > chip->size || address+length > chip->size) {
return ESP_ERR_INVALID_ARG;
}
@ -667,26 +688,24 @@ esp_err_t IRAM_ATTR esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address
* is no way to support non-standard chips. We use the legacy
* implementation and skip the chip and driver layers.
*/
if (chip == NULL) {
chip = esp_flash_default_chip;
} else if (chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) return err;
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_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_io_mode);
esp_flash_io_mode_t io_mode;
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->get_io_mode(chip, &io_mode);
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
if (err == ESP_OK) {
*qe = (io_mode == SPI_FLASH_QOUT);
}
@ -695,14 +714,16 @@ IRAM_ATTR esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe)
IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
{
VERIFY_OP(set_io_mode);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_io_mode);
chip->read_mode = (qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD);
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->set_io_mode(chip);
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL

View File

@ -116,8 +116,7 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
return ESP_ERR_INVALID_ARG;
}
esp_flash_t *chip = NULL;
spi_flash_host_driver_t *host = NULL;
memspi_host_data_t *host_data = NULL;
memspi_host_inst_t *host = NULL;
esp_err_t ret = ESP_OK;
uint32_t caps = MALLOC_CAP_DEFAULT;
@ -129,23 +128,16 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
goto fail;
}
host = (spi_flash_host_driver_t*)heap_caps_malloc(sizeof(spi_flash_host_driver_t), caps);
host = (memspi_host_inst_t*)heap_caps_malloc(sizeof(memspi_host_inst_t), caps);
*chip = (esp_flash_t) {
.read_mode = config->io_mode,
.host = host,
.host = (spi_flash_host_inst_t*)host,
};
if (!host) {
ret = ESP_ERR_NO_MEM;
goto fail;
}
host_data = (memspi_host_data_t*)heap_caps_malloc(sizeof(memspi_host_data_t), caps);
host->driver_data = host_data;
if (!host_data) {
ret = ESP_ERR_NO_MEM;
goto fail;
}
int dev_id = -1;
esp_err_t err = esp_flash_init_os_functions(chip, config->host_id, &dev_id);
if (err == ESP_ERR_NOT_SUPPORTED) {
@ -173,7 +165,7 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
.input_delay_ns = config->input_delay_ns,
.speed = config->speed,
};
err = memspi_host_init_pointers(host, host_data, &host_cfg);
err = memspi_host_init_pointers(host, &host_cfg);
if (err != ESP_OK) {
ret = err;
goto fail;
@ -195,10 +187,7 @@ esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip)
return ESP_ERR_INVALID_ARG;
}
esp_flash_deinit_os_functions(chip);
if (chip->host) {
free(chip->host->driver_data);
free(chip->host);
}
free(chip->host);
free(chip);
return ESP_OK;
}
@ -209,13 +198,11 @@ extern const esp_flash_os_functions_t esp_flash_noos_functions;
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
static DRAM_ATTR memspi_host_data_t default_driver_data;
static DRAM_ATTR spi_flash_host_driver_t esp_flash_default_host_drv = ESP_FLASH_DEFAULT_HOST_DRIVER();
static DRAM_ATTR memspi_host_inst_t esp_flash_default_host;
static DRAM_ATTR esp_flash_t default_chip = {
.read_mode = DEFAULT_FLASH_MODE,
.host = &esp_flash_default_host_drv,
.host = (spi_flash_host_inst_t*)&esp_flash_default_host,
.os_func = &esp_flash_noos_functions,
};
@ -229,12 +216,14 @@ esp_err_t esp_flash_init_default_chip(void)
#endif
//the host is already initialized, only do init for the data and load it to the host
spi_flash_hal_init(&default_driver_data, &cfg);
default_chip.host->driver_data = &default_driver_data;
esp_err_t err = memspi_host_init_pointers(&esp_flash_default_host, &cfg);
if (err != ESP_OK) {
return err;
}
// 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
esp_err_t err = esp_flash_init(&default_chip);
err = esp_flash_init(&default_chip);
if (err != ESP_OK) {
return err;
}

View File

@ -34,7 +34,15 @@ typedef struct {
uint32_t size; ///< Size of the region
} esp_flash_region_t;
/** OS-level integration hooks for accessing flash chips inside a running OS */
/** @brief OS-level integration hooks for accessing flash chips inside a running OS
*
* It's in the public header because some instances should be allocated statically in the startup
* code. May be updated according to hardware version and new flash chip feature requirements,
* shouldn't be treated as public API.
*
* For advanced developers, you may replace some of them with your implementations at your own
* risk.
*/
typedef struct {
/**
* Called before commencing any flash operation. Does not need to be
@ -51,16 +59,28 @@ typedef struct {
/** Delay for at least 'us' microseconds. Called in between 'start' and 'end'. */
esp_err_t (*delay_us)(void *arg, unsigned us);
/** Called for get temp buffer when buffer from application cannot be directly read into/write from. */
void *(*get_temp_buffer)(void* arg, size_t reqest_size, size_t* out_size);
/** Called for release temp buffer. */
void (*release_temp_buffer)(void* arg, void *temp_buf);
/** Yield to other tasks. Called during erase operations. */
esp_err_t (*yield)(void *arg);
} esp_flash_os_functions_t;
/** @brief Structure to describe a SPI flash chip connected to the system.
Structure must be initialized before use (passed to esp_flash_init()).
Structure must be initialized before use (passed to esp_flash_init()). It's in the public
header because some instances should be allocated statically in the startup code. May be
updated according to hardware version and new flash chip feature requirements, shouldn't be
treated as public API.
For advanced developers, you may replace some of them with your implementations at your own
risk.
*/
struct esp_flash_t {
spi_flash_host_driver_t *host; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used.
spi_flash_host_inst_t* host; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used.
const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adapter" structure. If NULL, will be detected during initialisation.
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.

View File

@ -28,9 +28,9 @@
.supports_direct_write = spi_flash_hal_supports_direct_write, \
.supports_direct_read = spi_flash_hal_supports_direct_read, \
.program_page = spi_flash_hal_program_page, \
.max_write_bytes = SPI_FLASH_HAL_MAX_WRITE_BYTES, \
.write_data_slicer = memspi_host_write_data_slicer, \
.read = spi_flash_hal_read, \
.max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES, \
.read_data_slicer = memspi_host_read_data_slicer, \
.host_idle = spi_flash_hal_host_idle, \
.configure_host_io_mode = spi_flash_hal_configure_host_io_mode, \
.poll_cmd_done = spi_flash_hal_poll_cmd_done, \
@ -38,20 +38,19 @@
}
/// configuration for the memspi host
typedef spi_flash_memspi_config_t memspi_host_config_t;
typedef spi_flash_hal_config_t memspi_host_config_t;
/// context for the memspi host
typedef spi_flash_memspi_data_t memspi_host_data_t;
typedef spi_flash_hal_context_t memspi_host_inst_t;
/**
* Initialize the memory SPI host.
*
* @param host Pointer to the host structure.
* @param data Pointer to allocated space to hold the context of host driver.
* @param cfg Pointer to configuration structure
*
* @return always return ESP_OK
*/
esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg);
esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg);
/*******************************************************************************
* NOTICE
@ -66,7 +65,7 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d
* High speed implementation of RDID through memspi interface relying on the
* ``common_command``.
*
* @param driver The driver context.
* @param host The driver context.
* @param id Output of the read ID from the slave.
*
* @return
@ -74,69 +73,106 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d
* - ESP_ERR_FLASH_NO_RESPONSE: if no response from chip
* - or other cases from ``spi_hal_common_command``
*/
esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *driver, uint32_t *id);
esp_err_t memspi_host_read_id_hs(spi_flash_host_inst_t *host, uint32_t *id);
/**
* High speed implementation of RDSR through memspi interface relying on the
* ``common_command``.
*
* @param driver The driver context.
* @param host The driver context.
* @param id Output of the read ID from the slave.
*
* @return
* - ESP_OK: if success
* - or other cases from ``spi_hal_common_command``
*/
esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr);
esp_err_t memspi_host_read_status_hs(spi_flash_host_inst_t *host, uint8_t *out_sr);
/**
* Flush the cache (if needed) after the contents are modified.
*
* @param driver The driver context.
* @param host The driver context.
* @param addr Start address of the modified region
* @param size Size of the region modified.
*
* @return always ESP_OK.
*/
esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size);
esp_err_t memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size);
/**
* Erase contents of entire chip.
*
* @param driver The driver context.
* @param host The driver context.
*/
void memspi_host_erase_chip(spi_flash_host_driver_t *driver);
void memspi_host_erase_chip(spi_flash_host_inst_t *host);
/**
* Erase a sector starting from a given address.
*
* @param driver The driver context.
* @param host The driver context.
* @param start_address Starting address of the sector.
*/
void memspi_host_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address);
void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a block starting from a given address.
*
* @param driver The driver context.
* @param host The driver context.
* @param start_address Starting address of the block.
*/
void memspi_host_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address);
void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Program a page with contents of a buffer.
*
* @param driver The driver context.
* @param host The driver context.
* @param buffer Buffer which contains the data to be flashed.
* @param address Starting address of where to flash the data.
* @param length The number of bytes to flash.
*/
void memspi_host_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length);
void memspi_host_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/**
* Set ability to write to chip.
*
* @param driver The driver context.
* @param host The driver context.
* @param wp Enable or disable write protect (true - enable, false - disable).
*/
esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *driver, bool wp);
esp_err_t memspi_host_set_write_protect(spi_flash_host_inst_t *host, bool wp);
/**
* Read data to buffer.
*
* @param host The driver context.
* @param buffer Buffer which contains the data to be read.
* @param address Starting address of where to read the data.
* @param length The number of bytes to read.
*/
esp_err_t memspi_host_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/**
* @brief Slicer for read data used in non-encrypted regions. This slicer does nothing but
* limit the length to the maximum size the host supports.
*
* @param address Flash address to read
* @param len Length to read
* @param align_address Output of the address to read, should be equal to the input `address`
* @param page_size Physical SPI flash page size
*
* @return Length that can actually be read in one `read` call in `spi_flash_host_driver_t`.
*/
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);
/**
* @brief Slicer for write data used in non-encrypted regions. This slicer limit the length to the
* maximum size the host supports, and truncate if the write data lie accross the page boundary
* (256 bytes)
*
* @param address Flash address to write
* @param len Length to write
* @param align_address Output of the address to write, should be equal to the input `address`
* @param page_size Physical SPI flash page size
*
* @return Length that can actually be written in one `program_page` call in `spi_flash_host_driver_t`.
*/
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);

View File

@ -19,6 +19,16 @@ struct esp_flash_t;
typedef struct esp_flash_t esp_flash_t;
typedef struct spi_flash_chip_t spi_flash_chip_t;
/** Timeout configurations for flash operations, all in us */
typedef struct {
uint32_t chip_erase_timeout; ///< Timeout for chip erase operation
uint32_t block_erase_timeout; ///< Timeout for block erase operation
uint32_t sector_erase_timeout; ///< Timeout for sector erase operation
uint32_t idle_timeout; ///< Default timeout for other commands to be sent by host and get done by flash
uint32_t page_program_timeout; ///< Timeout for page program operation
} flash_chip_op_timeout_t;
/** @brief SPI flash chip driver definition structure.
*
* The chip driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some
@ -38,6 +48,7 @@ typedef struct spi_flash_chip_t spi_flash_chip_t;
*/
struct spi_flash_chip_t {
const char *name; ///< Name of the chip driver
const flash_chip_op_timeout_t *timeout; ///< Timeout configuration for this chip
/* Probe to detect if a supported SPI flash chip is found.
*
* Attempts to configure 'chip' with these operations and probes for a matching SPI flash chip.

View File

@ -368,3 +368,6 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
* - 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);
/// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@ -19,73 +19,67 @@
#include "cache_utils.h"
#include "esp_flash_partitions.h"
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
#define SPI_FLASH_HAL_MAX_READ_BYTES 64
static const char TAG[] = "memspi";
static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
DRAM_ATTR static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
#ifdef CONFIG_IDF_TARGET_ESP32S2
extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_driver_t *driver);
extern esp_err_t spi_flash_hal_gpspi_device_config(spi_flash_host_driver_t *driver);
extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_inst_t *host);
extern esp_err_t spi_flash_hal_gpspi_device_config(spi_flash_host_inst_t *host);
esp_err_t spi_flash_hal_gpspi_configure_host_io_mode(
spi_flash_host_driver_t *host,
spi_flash_host_inst_t *host,
uint32_t command,
uint32_t addr_bitlen,
int dummy_cyclelen_base,
esp_flash_io_mode_t io_mode);
extern esp_err_t spi_flash_hal_gpspi_common_command(spi_flash_host_driver_t *chip_drv, spi_flash_trans_t *trans);
extern esp_err_t spi_flash_hal_gpspi_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len);
extern bool spi_flash_hal_gpspi_host_idle(spi_flash_host_driver_t *chip_drv);
extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *driver, const void *p);
extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *driver, const void *p);
extern esp_err_t spi_flash_hal_gpspi_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans);
extern esp_err_t spi_flash_hal_gpspi_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
extern bool spi_flash_hal_gpspi_host_idle(spi_flash_host_inst_t *host);
extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_inst_t *host, const void *p);
extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_inst_t *host, const void *p);
/** Default configuration for GPSPI */
static const spi_flash_host_driver_t esp_flash_gpspi_host = {
.dev_config = spi_flash_hal_gpspi_device_config,
.common_command = spi_flash_hal_gpspi_common_command,
.read_id = memspi_host_read_id_hs,
.erase_chip = memspi_host_erase_chip,
.erase_sector = memspi_host_erase_sector,
.erase_block = memspi_host_erase_block,
.read_status = memspi_host_read_status_hs,
.set_write_protect = memspi_host_set_write_protect,
.supports_direct_write = spi_flash_hal_gpspi_supports_direct_write,
.supports_direct_read = spi_flash_hal_gpspi_supports_direct_read,
.program_page = memspi_host_program_page,
.max_write_bytes = SPI_FLASH_HAL_MAX_WRITE_BYTES,
.read = spi_flash_hal_gpspi_read,
.max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES,
.host_idle = spi_flash_hal_gpspi_host_idle,
.configure_host_io_mode = spi_flash_hal_gpspi_configure_host_io_mode,
.poll_cmd_done = spi_flash_hal_gpspi_poll_cmd_done,
.flush_cache = NULL,
static const spi_flash_host_driver_t esp_flash_gpspi_host = {
.dev_config = spi_flash_hal_gpspi_device_config,
.common_command = spi_flash_hal_gpspi_common_command,
.read_id = memspi_host_read_id_hs,
.erase_chip = memspi_host_erase_chip,
.erase_sector = memspi_host_erase_sector,
.erase_block = memspi_host_erase_block,
.read_status = memspi_host_read_status_hs,
.set_write_protect = memspi_host_set_write_protect,
.supports_direct_write = spi_flash_hal_gpspi_supports_direct_write,
.supports_direct_read = spi_flash_hal_gpspi_supports_direct_read,
.program_page = memspi_host_program_page,
.write_data_slicer = memspi_host_write_data_slicer,
.read = spi_flash_hal_gpspi_read,
.read_data_slicer = memspi_host_read_data_slicer,
.host_idle = spi_flash_hal_gpspi_host_idle,
.configure_host_io_mode = spi_flash_hal_gpspi_configure_host_io_mode,
.poll_cmd_done = spi_flash_hal_gpspi_poll_cmd_done,
.flush_cache = NULL,
};
#endif
esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg)
esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg)
{
#ifdef CONFIG_IDF_TARGET_ESP32
memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t));
host->inst.driver = &esp_flash_default_host;
#elif CONFIG_IDF_TARGET_ESP32S2
if (cfg->host_id == SPI_HOST)
memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t));
host->inst.driver = &esp_flash_default_host;
else {
memcpy(host, &esp_flash_gpspi_host, sizeof(spi_flash_host_driver_t));
host->inst.driver = &esp_flash_gpspi_host;
}
#endif
esp_err_t err = spi_flash_hal_init(data, cfg);
if (err != ESP_OK) {
return err;
}
host->driver_data = data;
//some functions are not required if not SPI1
if ((void*)data->spi != (void*)spi_flash_ll_get_hw(SPI_HOST)) {
host->flush_cache = NULL;
}
return ESP_OK;
esp_err_t err = spi_flash_hal_init(host, cfg);
return err;
}
esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id)
esp_err_t memspi_host_read_id_hs(spi_flash_host_inst_t *host, uint32_t *id)
{
uint32_t id_buf = 0;
spi_flash_trans_t t = {
@ -93,7 +87,7 @@ esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id)
.miso_len = 3,
.miso_data = ((uint8_t*) &id_buf),
};
host->common_command(host, &t);
host->driver->common_command(host, &t);
uint32_t raw_flash_id = id_buf;
ESP_EARLY_LOGV(TAG, "raw_chip_id: %X\n", raw_flash_id);
@ -109,7 +103,7 @@ esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id)
return ESP_OK;
}
esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr)
esp_err_t memspi_host_read_status_hs(spi_flash_host_inst_t *host, uint8_t *out_sr)
{
//NOTE: we do have a read id function, however it doesn't work in high freq
uint32_t stat_buf = 0;
@ -118,7 +112,7 @@ esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *o
.miso_data = ((uint8_t*) &stat_buf),
.miso_len = 1
};
esp_err_t err = driver->common_command(driver, &t);
esp_err_t err = host->driver->common_command(host, &t);
if (err != ESP_OK) {
return err;
}
@ -126,70 +120,92 @@ esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *o
return ESP_OK;
}
esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size)
esp_err_t memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size)
{
if ((void*)((memspi_host_data_t*)(driver->driver_data))->spi == (void*) spi_flash_ll_get_hw(SPI_HOST)) {
if ((void*)((memspi_host_inst_t*)host)->spi == (void*) spi_flash_ll_get_hw(SPI_HOST)) {
spi_flash_check_and_flush_cache(addr, size);
}
return ESP_OK;
}
void memspi_host_erase_chip(spi_flash_host_driver_t *chip_drv)
void memspi_host_erase_chip(spi_flash_host_inst_t *host)
{
spi_flash_trans_t t = { 0 };
t.command = CMD_CHIP_ERASE;
chip_drv->common_command(chip_drv, &t);
host->driver->common_command(host, &t);
}
void memspi_host_erase_sector(spi_flash_host_driver_t *chip_drv, uint32_t start_address)
void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{
spi_flash_trans_t t = {
spi_flash_trans_t t = {
.command = CMD_SECTOR_ERASE,
.address_bitlen = 24,
.address = start_address
};
chip_drv->common_command(chip_drv, &t);
host->driver->common_command(host, &t);
}
void memspi_host_erase_block(spi_flash_host_driver_t *chip_drv, uint32_t start_address)
void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{
spi_flash_trans_t t = {
spi_flash_trans_t t = {
.command = CMD_LARGE_BLOCK_ERASE,
.address_bitlen = 24,
.address = start_address,
};
chip_drv->common_command(chip_drv, &t);
host->driver->common_command(host, &t);
}
void memspi_host_program_page(spi_flash_host_driver_t *chip_drv, const void *buffer, uint32_t address, uint32_t length)
void memspi_host_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{
spi_flash_trans_t t = {
spi_flash_trans_t t = {
.command = CMD_PROGRAM_PAGE,
.address_bitlen = 24,
.address = address,
.mosi_len = length,
.mosi_data = buffer
};
chip_drv->common_command(chip_drv, &t);
host->driver->common_command(host, &t);
}
esp_err_t memspi_host_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len)
esp_err_t memspi_host_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
{
spi_flash_trans_t t = {
.command = CMD_READ,
.address_bitlen = 24,
.address = address,
.miso_len = read_len,
.miso_data = buffer
};
chip_drv->common_command(chip_drv, &t);
host->driver->common_command(host, &t);
return ESP_OK;
}
esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp)
esp_err_t memspi_host_set_write_protect(spi_flash_host_inst_t *host, bool wp)
{
spi_flash_trans_t t = {
.command = wp ? CMD_WRDI : CMD_WREN
};
chip_drv->common_command(chip_drv, &t);
host->driver->common_command(host, &t);
return ESP_OK;
}
// When encryption is enabled, etc. the data slicer may be complicated
// 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 align_addr = address;
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;
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 max_len = SPI_FLASH_HAL_MAX_READ_BYTES;
*align_address = address;
return MIN(max_len, len);
}

View File

@ -78,6 +78,7 @@ static const char chip_name[] = "gd";
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_gd = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_gd_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,

View File

@ -13,13 +13,38 @@
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <sys/param.h> // For MIN/MAX
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#include "esp_log.h"
#include "esp_attr.h"
static const char TAG[] = "chip_generic";
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,
.qio_dummy_bitlen = SPI_FLASH_QIO_DUMMY_BITLEN,
.qout_dummy_bitlen = SPI_FLASH_QOUT_DUMMY_BITLEN,
.dout_dummy_bitlen = SPI_FLASH_DOUT_DUMMY_BITLEN,
.fastrd_dummy_bitlen = SPI_FLASH_FASTRD_DUMMY_BITLEN,
.slowrd_dummy_bitlen = SPI_FLASH_SLOWRD_DUMMY_BITLEN,
};
DRAM_ATTR flash_chip_dummy_t *rom_flash_chip_dummy = (flash_chip_dummy_t *)&default_flash_chip_dummy;
#define SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS 200
#define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS 4000
#define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS 500 //according to GD25Q127 + 100ms
@ -29,6 +54,13 @@ static const char TAG[] = "chip_generic";
#define HOST_DELAY_INTERVAL_US 1
#define CHIP_WAIT_IDLE_INTERVAL_US 20
const DRAM_ATTR flash_chip_op_timeout_t spi_flash_chip_generic_timeout = {
.chip_erase_timeout = SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS * 1000,
.block_erase_timeout = SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT_MS * 1000,
.sector_erase_timeout = SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS * 1000,
.idle_timeout = SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000,
.page_program_timeout = SPI_FLASH_GENERIC_PAGE_PROGRAM_TIMEOUT_MS * 1000,
};
esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id)
{
@ -44,7 +76,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip)
t = (spi_flash_trans_t) {
.command = CMD_RST_EN,
};
esp_err_t err = chip->host->common_command(chip->host, &t);
esp_err_t err = chip->host->driver->common_command(chip->host, &t);
if (err != ESP_OK) {
return err;
}
@ -52,12 +84,12 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip)
t = (spi_flash_trans_t) {
.command = CMD_RST_DEV,
};
err = chip->host->common_command(chip->host, &t);
err = chip->host->driver->common_command(chip->host, &t);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
return err;
}
@ -68,7 +100,7 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size)
/* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or
* 0xC0 or similar. */
if ((id & 0x0F00) != 0) {
if (((id & 0xFFFF) == 0x0000) || ((id & 0xFFFF) == 0xFFFF)) {
return ESP_ERR_FLASH_UNSUPPORTED_CHIP;
}
@ -83,18 +115,18 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
chip->host->erase_chip(chip->host);
chip->host->driver->erase_chip(chip->host);
//to save time, flush cache here
if (chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, 0, chip->size);
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, 0, chip->size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->chip_erase_timeout);
}
return err;
}
@ -103,18 +135,18 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
chip->host->erase_sector(chip->host, start_address);
chip->host->driver->erase_sector(chip->host, start_address);
//to save time, flush cache here
if (chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->sector_erase_timeout);
}
return err;
}
@ -123,18 +155,18 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
chip->host->erase_block(chip->host, start_address);
chip->host->driver->erase_block(chip->host, start_address);
//to save time, flush cache here
if (chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->block_erase_timeout);
}
return err;
}
@ -142,6 +174,10 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
esp_err_t spi_flash_chip_generic_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
err = spi_flash_chip_generic_config_host_io_mode(chip);
@ -151,12 +187,17 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
}
while (err == ESP_OK && length > 0) {
uint32_t read_len = MIN(length, chip->host->max_read_bytes);
err = chip->host->read(chip->host, buffer, address, read_len);
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);
buffer += read_len;
length -= read_len;
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;
@ -166,13 +207,13 @@ esp_err_t spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buf
{
esp_err_t err;
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) {
// Perform the actual Page Program command
chip->host->program_page(chip->host, buffer, address, length);
chip->host->driver->program_page(chip->host, buffer, address, length);
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_PAGE_PROGRAM_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
}
return err;
}
@ -181,25 +222,27 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui
{
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) {
uint32_t page_len = MIN(chip->host->max_write_bytes, MIN(page_size, length));
if ((address + page_len) / page_size != address / page_size) {
// Most flash chips can't page write across a page boundary
page_len = page_size - (address % page_size);
}
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);
if (err == ESP_OK) {
err = chip->chip_drv->program_page(chip, buffer, address, page_len);
address += page_len;
buffer = (void *)((intptr_t)buffer + page_len);
length -= page_len;
address += write_len;
buffer = (void *)((intptr_t)buffer + write_len);
length -= write_len;
}
}
if (err == ESP_OK && chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, address, length);
if (err == ESP_OK && chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, address, length);
}
return err;
}
@ -213,10 +256,10 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write
{
esp_err_t err = ESP_OK;
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) {
chip->host->set_write_protect(chip->host, write_protect);
chip->host->driver->set_write_protect(chip->host, write_protect);
}
bool wp_read;
@ -233,7 +276,7 @@ esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_
esp_err_t err = ESP_OK;
uint8_t status;
assert(out_write_protect!=NULL);
err = chip->host->read_status(chip->host, &status);
err = chip->host->driver->read_status(chip->host, &status);
if (err != ESP_OK) {
return err;
}
@ -244,7 +287,7 @@ esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_
esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_us)
{
while (chip->host->host_idle(chip->host) && *timeout_us > 0) {
while (chip->host->driver->host_idle(chip->host) && *timeout_us > 0) {
#if HOST_DELAY_INTERVAL_US > 0
if (*timeout_us > 1) {
int delay = MIN(HOST_DELAY_INTERVAL_US, *timeout_us);
@ -271,7 +314,7 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return err;
}
err = chip->host->read_status(chip->host, &status);
err = chip->host->driver->read_status(chip->host, &status);
if (err != ESP_OK) {
return err;
}
@ -298,40 +341,40 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip)
case SPI_FLASH_QIO:
//for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_QIO_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_QIO_DUMMY_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->qio_dummy_bitlen;
read_command = CMD_FASTRD_QIO;
break;
case SPI_FLASH_QOUT:
addr_bitlen = SPI_FLASH_QOUT_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_QOUT_DUMMY_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->qout_dummy_bitlen;
read_command = CMD_FASTRD_QUAD;
break;
case SPI_FLASH_DIO:
//for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_DIO_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_DIO_DUMMY_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->dio_dummy_bitlen;
read_command = CMD_FASTRD_DIO;
break;
case SPI_FLASH_DOUT:
addr_bitlen = SPI_FLASH_DOUT_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_DOUT_DUMMY_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->dout_dummy_bitlen;
read_command = CMD_FASTRD_DUAL;
break;
case SPI_FLASH_FASTRD:
addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_FASTRD_DUMMY_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->fastrd_dummy_bitlen;
read_command = CMD_FASTRD;
break;
case SPI_FLASH_SLOWRD:
addr_bitlen = SPI_FLASH_SLOWRD_ADDR_BITLEN;
dummy_cyclelen_base = SPI_FLASH_SLOWRD_DUMMY_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->slowrd_dummy_bitlen;
read_command = CMD_READ;
break;
default:
return ESP_ERR_FLASH_NOT_INITIALISED;
}
return chip->host->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base,
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base,
chip->read_mode);
}
@ -364,6 +407,7 @@ static const char chip_name[] = "generic";
const spi_flash_chip_t esp_flash_chip_generic = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_generic_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
@ -407,7 +451,7 @@ static esp_err_t spi_flash_common_read_qe_sr(esp_flash_t *chip, uint8_t qe_rdsr_
.miso_data = (uint8_t*) &sr_buf,
.miso_len = qe_sr_bitwidth / 8,
};
esp_err_t ret = chip->host->common_command(chip->host, &t);
esp_err_t ret = chip->host->driver->common_command(chip->host, &t);
*sr = sr_buf;
return ret;
}
@ -420,7 +464,7 @@ static esp_err_t spi_flash_common_write_qe_sr(esp_flash_t *chip, uint8_t qe_wrsr
.mosi_len = qe_sr_bitwidth / 8,
.miso_len = 0,
};
return chip->host->common_command(chip->host, &t);
return chip->host->driver->common_command(chip->host, &t);
}
esp_err_t spi_flash_common_read_status_16b_rdsr_rdsr2(esp_flash_t* chip, uint32_t* out_sr)
@ -505,7 +549,7 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
return ret;
}
ret = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
ret = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (ret != ESP_OK) {
return ret;
}

View File

@ -64,6 +64,7 @@ static const char chip_name[] = "issi";
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_issi = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_issi_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,

View File

@ -42,6 +42,7 @@ static const char chip_name[] = "mxic";
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_mxic = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_mxic_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,

View File

@ -13,6 +13,7 @@
// limitations under the License.
#include <stdarg.h>
#include <sys/param.h> //For max/min
#include "esp_attr.h"
#include "esp_spi_flash.h" //for ``g_flash_guard_default_ops``
#include "esp_flash.h"
@ -21,6 +22,7 @@
#include "freertos/task.h"
#include "hal/spi_types.h"
#include "sdkconfig.h"
#include "esp_log.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/ets_sys.h"
@ -30,6 +32,7 @@
#include "driver/spi_common_internal.h"
static const char TAG[] = "spi_flash";
/*
* OS functions providing delay service and arbitration among chips, and with the cache.
@ -102,7 +105,6 @@ static IRAM_ATTR esp_err_t delay_us(void *arg, unsigned us)
ets_delay_us(us);
return ESP_OK;
}
static IRAM_ATTR esp_err_t spi_flash_os_yield(void *arg)
{
#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE
@ -111,6 +113,32 @@ static IRAM_ATTR esp_err_t spi_flash_os_yield(void *arg)
return ESP_OK;
}
static IRAM_ATTR void* get_buffer_malloc(void* arg, size_t reqest_size, size_t* out_size)
{
/* Allocate temporary internal buffer to use for the actual read. If the preferred size
doesn't fit in free internal memory, allocate the largest available free block.
(May need to shrink read_chunk_size and retry due to race conditions with other tasks
also allocating from the heap.)
*/
void* ret = NULL;
unsigned retries = 5;
size_t read_chunk_size = reqest_size;
while(ret == NULL && retries--) {
read_chunk_size = MIN(read_chunk_size, heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
read_chunk_size = (read_chunk_size + 3) & ~3;
ret = heap_caps_malloc(read_chunk_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}
ESP_LOGV(TAG, "allocate temp buffer: %p (%d)", ret, read_chunk_size);
*out_size = (ret != NULL? read_chunk_size: 0);
return ret;
}
static IRAM_ATTR void release_buffer_malloc(void* arg, void *temp_buf)
{
free(temp_buf);
}
static IRAM_ATTR esp_err_t main_flash_region_protected(void* arg, size_t start_addr, size_t size)
{
if (((spi1_app_func_arg_t*)arg)->no_protect || esp_partition_main_flash_region_safe(start_addr, size)) {
@ -129,6 +157,8 @@ static const DRAM_ATTR esp_flash_os_functions_t esp_flash_spi1_default_os_functi
.end = spi1_end,
.region_protected = main_flash_region_protected,
.delay_us = delay_us,
.get_temp_buffer = get_buffer_malloc,
.release_temp_buffer = release_buffer_malloc,
.yield = spi_flash_os_yield,
};
@ -136,6 +166,8 @@ static const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = {
.start = spi_start,
.end = spi_end,
.delay_us = delay_us,
.get_temp_buffer = get_buffer_malloc,
.release_temp_buffer = release_buffer_malloc,
.yield = spi_flash_os_yield
};

View File

@ -31,7 +31,7 @@
typedef struct {
uint32_t icache_autoload;
uint32_t dcache_autoload;
} spi_noos_arg_t;
} spi_noos_arg_t;
static DRAM_ATTR spi_noos_arg_t spi_arg = { 0 };
#endif
@ -71,11 +71,19 @@ static IRAM_ATTR esp_err_t delay_us(void *arg, unsigned us)
return ESP_OK;
}
// Currently when the os is not up yet, the caller is supposed to call esp_flash APIs with proper
// buffers.
IRAM_ATTR void* get_temp_buffer_not_supported(void* arg, size_t reqest_size, size_t* out_size)
{
return NULL;
}
const DRAM_ATTR esp_flash_os_functions_t esp_flash_noos_functions = {
.start = start,
.end = end,
.delay_us = delay_us,
.region_protected = NULL,
.get_temp_buffer = get_temp_buffer_not_supported,
.yield = NULL,
};

View File

@ -8,6 +8,7 @@
#include "esp_flash.h"
#include "driver/spi_common_internal.h"
#include "esp_flash_spi_init.h"
#include "memspi_host_driver.h"
#include <esp_attr.h>
#include "esp_log.h"
@ -18,7 +19,6 @@
#include "soc/io_mux_reg.h"
#include "sdkconfig.h"
#include "hal/spi_flash_hal.h"
#include "ccomp_timer.h"
#include "esp_rom_gpio.h"
@ -175,9 +175,9 @@ static void get_chip_host(esp_flash_t* chip, spi_host_device_t* out_host_id, int
host_id = SPI_HOST;
cs_id = 0;
} else {
spi_flash_memspi_data_t* driver_data = (spi_flash_memspi_data_t*)chip->host->driver_data;
host_id = spi_flash_ll_hw_get_id(driver_data->spi);
cs_id = driver_data->cs_num;
spi_flash_hal_context_t* host_data = (spi_flash_hal_context_t*)chip->host;
host_id = spi_flash_ll_hw_get_id(host_data->spi);
cs_id = host_data->cs_num;
}
if (out_host_id) {
*out_host_id = host_id;
@ -382,7 +382,8 @@ void test_simple_read_write(esp_flash_t *chip)
srand(test_seed);
for (int i = 0; i < sizeof(sector_buf); i++) {
TEST_ASSERT_EQUAL_HEX8(rand() & 0xFF, sector_buf[i]);
uint8_t data = rand();
TEST_ASSERT_EQUAL_HEX8(data, sector_buf[i]);
}
}
@ -412,17 +413,22 @@ FLASH_TEST_CASE_3("SPI flash unaligned read/write", test_unaligned_read_write);
void test_single_read_write(esp_flash_t* chip)
{
const int seed = 699;
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 2);
srand(seed);
for (unsigned v = 0; v < 512; v++) {
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_write(chip, &v, offs + v, 1) );
uint32_t data = rand();
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_write(chip, &data, offs + v, 1) );
}
srand(seed);
for (unsigned v = 0; v < 512; v++) {
uint8_t readback;
uint32_t data = rand();
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_read(chip, &readback, offs + v, 1) );
TEST_ASSERT_EQUAL_HEX8(v, readback);
TEST_ASSERT_EQUAL_HEX8(data, readback);
}
}
@ -435,18 +441,23 @@ FLASH_TEST_CASE_3("SPI flash single byte reads/writes", test_single_read_write);
*/
void test_three_byte_read_write(esp_flash_t *chip)
{
const int seed = 700;
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 2);
ets_printf("offs:%X\n", offs);
for (uint32_t v = 0; v < 2000; v++) {
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, &v, offs + 3 * v, 3) );
srand(seed);
for (uint32_t v = 0; v < 86; v++) {
uint32_t data = rand();
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, &data, offs + 3 * v, 3) );
}
for (uint32_t v = 0; v < 2000; v++) {
srand(seed);
for (uint32_t v = 0; v < 1; v++) {
uint32_t readback;
uint32_t data = rand();
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, offs + 3 * v, 3) );
TEST_ASSERT_EQUAL_HEX32(v & 0xFFFFFF, readback & 0xFFFFFF);
TEST_ASSERT_EQUAL_HEX32(data & 0xFFFFFF, readback & 0xFFFFFF);
}
}