esp_flash: refactor to be compatible with the latest ROM

Including:
1. Change the write bytes/read bytes parameter in the host driver into slicers to meet the requirements of complicated cases.
2. Refactor the esp_flash_api code a bit so that we can use the code in the ROM laster
3. Provide get_temp_buffer and release_temp_buffer in the os_functions when the buffer passed by application cannot be used directly.
4. Make timeout of operations configurable in the chip_driver.
5. Make dummy number configurable.
This commit is contained in:
Michael (XIAO Xufeng) 2020-04-30 10:37:35 +08:00
parent 9d21b17384
commit a9c8895bb2
13 changed files with 390 additions and 168 deletions

View File

@ -115,18 +115,36 @@ struct spi_flash_host_driver_t {
* 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 */
/** Check whether given buffer can be directly used 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;
/**
* 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)(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;
/** Check whether given buffer can be directly used to read */
bool (*supports_direct_read)(spi_flash_host_driver_t *driver, 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)(uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check whether the host is idle to perform new operations.
*/

View File

@ -71,12 +71,31 @@ _Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the i
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
static esp_err_t spiflash_start_default(esp_flash_t *chip);
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
typedef struct {
esp_err_t (*start)(esp_flash_t *chip);
esp_err_t (*end)(esp_flash_t *chip, esp_err_t err);
esp_err_t (*chip_check)(esp_flash_t **inout_chip);
} rom_spiflash_api_func_t;
// These functions can be placed in the ROM. For now we use the code in IDF.
DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
.start = spiflash_start_default,
.end = spiflash_end_default,
.chip_check = check_chip_pointer_default,
};
DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api;
/* Static function to notify OS of a new SPI flash operation.
If returns an error result, caller must abort. If returns ESP_OK, caller must
call spiflash_end() before returning.
call rom_spiflash_api_funcs->end() before returning.
*/
static esp_err_t IRAM_ATTR spiflash_start(esp_flash_t *chip)
static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip)
{
if (chip->os_func != NULL && chip->os_func->start != NULL) {
esp_err_t err = chip->os_func->start(chip->os_func_data);
@ -90,7 +109,7 @@ static esp_err_t IRAM_ATTR spiflash_start(esp_flash_t *chip)
/* 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);
@ -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,13 +199,13 @@ 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;
}
@ -189,7 +222,7 @@ esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id
}
}
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);
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,7 +546,8 @@ 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;
}
@ -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,7 +609,8 @@ 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;
@ -595,7 +619,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
//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);
esp_err_t err = ESP_OK;
err = ESP_OK;
/* Write output in chunks, either by buffering on stack or
by artificially cutting into MAX_WRITE_CHUNK parts (in an OS
environment, this prevents writing from causing interrupt or higher priority task
@ -613,7 +637,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
write_buf = buf;
}
err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
@ -624,7 +648,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
buffer = (void *)((intptr_t)buffer + write_len);
length -= write_len;
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
} while (err == ESP_OK && length > 0);
return err;
}
@ -639,11 +663,8 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres
* is no way to support non-standard chips. We use the legacy
* implementation and skip the chip and driver layers.
*/
if (chip == NULL) {
chip = esp_flash_default_chip;
} else if (chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) return err;
if (buffer == NULL || address > chip->size || address+length > chip->size) {
return ESP_ERR_INVALID_ARG;
}
@ -667,26 +688,24 @@ esp_err_t IRAM_ATTR esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address
* is no way to support non-standard chips. We use the legacy
* implementation and skip the chip and driver layers.
*/
if (chip == NULL) {
chip = esp_flash_default_chip;
} else if (chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) return err;
return spi_flash_read_encrypted(address, out_buffer, length);
}
// test only, non-public
IRAM_ATTR esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe)
{
VERIFY_OP(get_io_mode);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_io_mode);
esp_flash_io_mode_t io_mode;
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->get_io_mode(chip, &io_mode);
err = spiflash_end(chip, err);
err = rom_spiflash_api_funcs->end(chip, err);
if (err == ESP_OK) {
*qe = (io_mode == SPI_FLASH_QOUT);
}
@ -695,14 +714,16 @@ IRAM_ATTR esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe)
IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
{
VERIFY_OP(set_io_mode);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_io_mode);
chip->read_mode = (qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD);
esp_err_t err = spiflash_start(chip);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->set_io_mode(chip);
return spiflash_end(chip, err);
return rom_spiflash_api_funcs->end(chip, err);
}
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL

View File

@ -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,13 +59,25 @@ 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.

View File

@ -28,9 +28,9 @@
.supports_direct_write = spi_flash_hal_supports_direct_write, \
.supports_direct_read = spi_flash_hal_supports_direct_read, \
.program_page = spi_flash_hal_program_page, \
.max_write_bytes = SPI_FLASH_HAL_MAX_WRITE_BYTES, \
.write_data_slicer = memspi_host_write_data_slicer, \
.read = spi_flash_hal_read, \
.max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES, \
.read_data_slicer = memspi_host_read_data_slicer, \
.host_idle = spi_flash_hal_host_idle, \
.configure_host_io_mode = spi_flash_hal_configure_host_io_mode, \
.poll_cmd_done = spi_flash_hal_poll_cmd_done, \
@ -140,3 +140,40 @@ void memspi_host_program_page(spi_flash_host_driver_t *driver, const void *buffe
* @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);
/**
* Read data to buffer.
*
* @param driver 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_driver_t *driver, 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(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(uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size);

View File

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

View File

@ -368,3 +368,6 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
* - or other error passed from the ``configure_host_mode`` function of host driver
*/
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip);
/// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@ -19,6 +19,9 @@
#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();
@ -38,25 +41,25 @@ extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *d
extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *driver, 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
@ -143,7 +146,7 @@ void memspi_host_erase_chip(spi_flash_host_driver_t *chip_drv)
void memspi_host_erase_sector(spi_flash_host_driver_t *chip_drv, uint32_t start_address)
{
spi_flash_trans_t t = {
spi_flash_trans_t t = {
.command = CMD_SECTOR_ERASE,
.address_bitlen = 24,
.address = start_address
@ -153,7 +156,7 @@ void memspi_host_erase_sector(spi_flash_host_driver_t *chip_drv, uint32_t start_
void memspi_host_erase_block(spi_flash_host_driver_t *chip_drv, 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,
@ -163,7 +166,7 @@ void memspi_host_erase_block(spi_flash_host_driver_t *chip_drv, uint32_t start_a
void memspi_host_program_page(spi_flash_host_driver_t *chip_drv, 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,
@ -176,6 +179,7 @@ void memspi_host_program_page(spi_flash_host_driver_t *chip_drv, const void *buf
esp_err_t memspi_host_read(spi_flash_host_driver_t *chip_drv, 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,
@ -193,3 +197,24 @@ esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *chip_drv, bool
chip_drv->common_command(chip_drv, &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(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(uint32_t address, uint32_t len, uint32_t *align_address, uint32_t page_size)
{
// Shouldn't read longer than SPI_FLASH_HAL_MAX_READ_BYTES
uint32_t max_len = SPI_FLASH_HAL_MAX_READ_BYTES;
*align_address = address;
return MIN(max_len, len);
}

View File

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

View File

@ -13,13 +13,38 @@
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <sys/param.h> // For MIN/MAX
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#include "esp_log.h"
#include "esp_attr.h"
static const char TAG[] = "chip_generic";
typedef struct flash_chip_dummy {
uint8_t dio_dummy_bitlen;
uint8_t qio_dummy_bitlen;
uint8_t qout_dummy_bitlen;
uint8_t dout_dummy_bitlen;
uint8_t fastrd_dummy_bitlen;
uint8_t slowrd_dummy_bitlen;
} flash_chip_dummy_t;
// These parameters can be placed in the ROM. For now we use the code in IDF.
DRAM_ATTR const static flash_chip_dummy_t default_flash_chip_dummy = {
.dio_dummy_bitlen = SPI_FLASH_DIO_DUMMY_BITLEN,
.qio_dummy_bitlen = SPI_FLASH_QIO_DUMMY_BITLEN,
.qout_dummy_bitlen = SPI_FLASH_QOUT_DUMMY_BITLEN,
.dout_dummy_bitlen = SPI_FLASH_DOUT_DUMMY_BITLEN,
.fastrd_dummy_bitlen = SPI_FLASH_FASTRD_DUMMY_BITLEN,
.slowrd_dummy_bitlen = SPI_FLASH_SLOWRD_DUMMY_BITLEN,
};
DRAM_ATTR flash_chip_dummy_t *rom_flash_chip_dummy = (flash_chip_dummy_t *)&default_flash_chip_dummy;
#define SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS 200
#define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS 4000
#define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS 500 //according to GD25Q127 + 100ms
@ -29,6 +54,13 @@ static const char TAG[] = "chip_generic";
#define HOST_DELAY_INTERVAL_US 1
#define CHIP_WAIT_IDLE_INTERVAL_US 20
const DRAM_ATTR flash_chip_op_timeout_t spi_flash_chip_generic_timeout = {
.chip_erase_timeout = SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS * 1000,
.block_erase_timeout = SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT_MS * 1000,
.sector_erase_timeout = SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS * 1000,
.idle_timeout = SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000,
.page_program_timeout = SPI_FLASH_GENERIC_PAGE_PROGRAM_TIMEOUT_MS * 1000,
};
esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id)
{
@ -57,7 +89,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip)
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,7 +115,7 @@ 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);
@ -94,7 +126,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
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,7 +135,7 @@ 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);
@ -114,7 +146,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
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,7 +155,7 @@ 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);
@ -134,7 +166,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
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->read_data_slicer(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->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);
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,21 +222,23 @@ 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->write_data_slicer(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) {
@ -213,7 +256,7 @@ 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);
@ -298,33 +341,33 @@ 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:
@ -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,
@ -505,7 +549,7 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
return ret;
}
ret = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
ret = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (ret != ESP_OK) {
return ret;
}

View File

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

View File

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

View File

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

View File

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