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

@@ -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