mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
commit
79a5b0b5af
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
@ -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.
|
||||
|
@ -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;
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user