esp_flash:fix bug about clearing WLE automatically after actions

pull/6192/head
Cao Sen Miao 2020-09-18 14:32:37 +08:00
rodzic 1a35b5ac9b
commit 11188d2143
12 zmienionych plików z 176 dodań i 21 usunięć

Wyświetl plik

@ -543,6 +543,13 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp
*/
void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig);
/**
* @brief Clear WEL bit unconditionally.
*
* @return always ESP_ROM_SPIFLASH_RESULT_OK
*/
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void);
/** @brief Global esp_rom_spiflash_chip_t structure used by ROM functions
*
*/

Wyświetl plik

@ -554,6 +554,13 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp
*/
void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig);
/**
* @brief Clear WEL bit unconditionally.
*
* @return always ESP_ROM_SPIFLASH_RESULT_OK
*/
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void);
/** @brief Global esp_rom_spiflash_chip_t structure used by ROM functions
*
*/

Wyświetl plik

@ -541,6 +541,13 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp
*/
void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig);
/**
* @brief Clear WEL bit unconditionally.
*
* @return always ESP_ROM_SPIFLASH_RESULT_OK
*/
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void);
/** @brief Global esp_rom_spiflash_chip_t structure used by ROM functions
*
*/

Wyświetl plik

@ -3,9 +3,10 @@ if(BOOTLOADER_BUILD)
# ESP32 Bootloader needs SPIUnlock from this file, but doesn't
# need other parts of this component
set(srcs "esp32/spi_flash_rom_patch.c")
else()
# but on other platforms no source files are needed for bootloader
set(srcs)
elseif(CONFIG_IDF_TARGET_ESP32S2)
set(srcs "esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
set(srcs "esp32s3/spi_flash_rom_patch.c")
endif()
set(cache_srcs "")
set(priv_requires bootloader_support soc)
@ -22,6 +23,12 @@ else()
if(CONFIG_IDF_TARGET_ESP32)
list(APPEND srcs
"esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
list(APPEND srcs
"esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
list(APPEND srcs
"esp32s3/spi_flash_rom_patch.c")
endif()
# New implementation after IDF v4.0

Wyświetl plik

@ -14,6 +14,7 @@
#include "sdkconfig.h"
#include "esp32/rom/spi_flash.h"
#include "soc/spi_periph.h"
#include "spi_flash_defs.h"
#define SPI_IDX 1
@ -682,4 +683,11 @@ esp_rom_spiflash_result_t esp_rom_spiflash_erase_area(uint32_t start_addr, uint3
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void)
{
REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WRDI);
while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
#endif

Wyświetl plik

@ -0,0 +1,28 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include "esp32s2/rom/spi_flash.h"
#include "soc/spi_periph.h"
#include "spi_flash_defs.h"
#define SPI_IDX 1
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip;
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void)
{
REG_WRITE(SPI_MEM_CMD_REG(SPI_IDX), SPI_MEM_FLASH_WRDI);
while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0);
return ESP_ROM_SPIFLASH_RESULT_OK;
}

Wyświetl plik

@ -0,0 +1,28 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include "esp32s3/rom/spi_flash.h"
#include "soc/spi_periph.h"
#include "spi_flash_defs.h"
#define SPI_IDX 1
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip;
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void)
{
REG_WRITE(SPI_MEM_CMD_REG(SPI_IDX), SPI_MEM_FLASH_WRDI);
while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0);
return ESP_ROM_SPIFLASH_RESULT_OK;
}

Wyświetl plik

@ -289,6 +289,8 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size)
COUNTER_STOP(erase);
spi_flash_guard_start();
// Ensure WEL is 0 after the operation, even if the erase failed.
esp_rom_spiflash_write_disable();
spi_flash_check_and_flush_cache(start_addr, size);
spi_flash_guard_end();
@ -461,6 +463,8 @@ out:
COUNTER_STOP(write);
spi_flash_guard_start();
// Ensure WEL is 0 after the operation, even if the write failed.
esp_rom_spiflash_write_disable();
spi_flash_check_and_flush_cache(dst, size);
spi_flash_guard_end();
@ -491,6 +495,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src,
err = spi_flash_write_encrypted_chip(dest_addr, src, size);
COUNTER_ADD_BYTES(write, size);
spi_flash_guard_start();
esp_rom_spiflash_write_disable();
spi_flash_check_and_flush_cache(dest_addr, size);
spi_flash_guard_end();
#else
@ -525,6 +530,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src,
COUNTER_ADD_BYTES(write, size);
spi_flash_guard_start();
esp_rom_spiflash_write_disable();
spi_flash_check_and_flush_cache(dest_addr, size);
spi_flash_guard_end();

Wyświetl plik

@ -102,6 +102,8 @@ struct esp_flash_t {
esp_flash_io_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.
uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation.
uint32_t chip_id; ///< Detected chip id.
uint32_t busy :1; ///< This flag is used to verify chip's status.
uint32_t reserved_flags :31; ///< reserved.
};
@ -159,7 +161,10 @@ esp_err_t esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size);
* @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init()
*
*
* @return ESP_OK on success, or a flash error code if operation failed.
* @return
* - ESP_OK on success,
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - Other flash error code if operation failed.
*/
esp_err_t esp_flash_erase_chip(esp_flash_t *chip);
@ -176,7 +181,10 @@ esp_err_t esp_flash_erase_chip(esp_flash_t *chip);
* chip->drv->block_erase_size field, typically 65536 bytes). Remaining sectors are erased using individual sector erase
* commands.
*
* @return ESP_OK on success, or a flash error code if operation failed.
* @return
* - ESP_OK on success,
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - Other flash error code if operation failed.
*/
esp_err_t esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len);
@ -280,7 +288,10 @@ esp_err_t esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint
*
* There are no alignment constraints on buffer, address or length.
*
* @return ESP_OK on success, or a flash error code if operation failed.
* @return
* - ESP_OK on success,
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - Other flash error code if operation failed.
*/
esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);

Wyświetl plik

@ -72,6 +72,7 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size);
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_chip`` function of host driver
*/
esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip);
@ -84,6 +85,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip);
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_sector`` function of host driver
*/
esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address);
@ -96,6 +98,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_block`` function of host driver
*/
esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address);
@ -129,6 +132,7 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
*
* @return
* - ESP_OK if success
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation. This is indicated by WREN = 1 after the command is sent.
* - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver
*/
esp_err_t

Wyświetl plik

@ -110,4 +110,9 @@ void *heap_caps_malloc( size_t size, uint32_t caps )
return NULL;
}
esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void)
{
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_flash_t* esp_flash_default_chip = NULL;

Wyświetl plik

@ -117,14 +117,21 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
//The chip didn't accept the previous write command. Ignore this in preparation stage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
chip->host->driver->erase_chip(chip->host);
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
#else
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->chip_erase_timeout);
#endif
}
// Ensure WEL is 0, even if the erase failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
@ -134,14 +141,21 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
chip->host->driver->erase_sector(chip->host, start_address);
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
#else
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->sector_erase_timeout);
#endif
}
// Ensure WEL is 0, even if the erase failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
@ -151,14 +165,21 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
chip->host->driver->erase_block(chip->host, start_address);
chip->busy = 1;
#ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
err = chip->chip_drv->wait_idle(chip, ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
#else
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->block_erase_timeout);
#endif
}
// Ensure WEL is 0, even if the erase failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
@ -199,13 +220,18 @@ 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, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) {
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
// Perform the actual Page Program command
chip->host->driver->program_page(chip->host, buffer, address, length);
chip->busy = 1;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
}
// Ensure WEL is 0, even if the page program failed.
if (err == ESP_ERR_NOT_SUPPORTED) {
err = chip->chip_drv->set_chip_write_protect(chip, true);
}
return err;
}
@ -247,8 +273,8 @@ 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, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) {
//The chip didn't accept the previous write command. Ignore this in preparationstage.
if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
chip->host->driver->set_write_protect(chip->host, write_protect);
}
@ -264,9 +290,9 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write
esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect)
{
esp_err_t err = ESP_OK;
uint8_t status;
uint32_t status;
assert(out_write_protect!=NULL);
err = chip->host->driver->read_status(chip->host, &status);
err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &status);
if (err != ESP_OK) {
return err;
}
@ -344,8 +370,14 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
}
status = read;
if ((status & SR_WIP) == 0) {
break; // Write in progress is complete
if ((status & SR_WIP) == 0) { // Verify write in progress is complete
if (chip->busy == 1) {
chip->busy = 0;
if ((status & SR_WREN) != 0) { // The previous command is not accepted, leaving the WEL still set.
return ESP_ERR_NOT_SUPPORTED;
}
}
break;
}
if (timeout_us > 0 && interval > 0) {
int delay = MIN(interval, timeout_us);
@ -355,7 +387,6 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
}
}
}
return (timeout_us > 0) ? ESP_OK : ESP_ERR_TIMEOUT;
}
@ -587,11 +618,19 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
ret = (*wrsr_func)(chip, sr_update);
if (ret != ESP_OK) {
chip->chip_drv->set_chip_write_protect(chip, true);
return ret;
}
ret = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (ret != ESP_OK) {
if (ret == ESP_ERR_NOT_SUPPORTED) {
chip->chip_drv->set_chip_write_protect(chip, true);
}
/* This function is the fallback approach, so we give it higher tolerance.
* When the previous WRSR is rejected by the flash,
* the result of this function is determined by the result -whether the value of RDSR meets the expectation.
*/
if (ret != ESP_OK && ret != ESP_ERR_NOT_SUPPORTED) {
return ret;
}
@ -605,8 +644,6 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
if (sr != sr_update) {
ret = ESP_ERR_FLASH_NO_RESPONSE;
}
chip->chip_drv->set_chip_write_protect(chip, true);
}
return ret;
}