spi_flash(esp32-s2): Add the workaround of a reboot issue when SPI HW suspend is enabled

pull/6491/head
KonstantinKondrashov 2020-06-12 18:52:00 +08:00 zatwierdzone przez Cao Sen Miao
rodzic 60e58eaddb
commit 1f37a5f162
7 zmienionych plików z 134 dodań i 0 usunięć

Wyświetl plik

@ -117,6 +117,51 @@ static inline void spi_flash_ll_erase_block(spi_dev_t *dev)
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_suspend(spi_dev_t *dev)
{
dev->cmd.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_resume(spi_dev_t *dev)
{
dev->cmd.flash_per = 1;
}
/**
* Initialize auto wait idle mode. (work only for ESP32-S2)
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
#define spi_flash_ll_auto_wait_idle_init(...) ()
/**
* Initialize auto wait idle mode (work only for ESP32-S2)
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
#define spi_flash_ll_auto_suspend_init(...) ()
/**
* Return the suspend status of erase or program operations. (work only for ESP32-S2)
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
#define spi_flash_ll_sus_status(...) ({false;})
/**
* Enable/disable write protection for the flash chip.
*

Wyświetl plik

@ -83,6 +83,8 @@ typedef union {
#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_sector(dev) spimem_flash_ll_erase_sector((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_block(dev) spimem_flash_ll_erase_block((spi_mem_dev_t*)dev)
#define spi_flash_ll_suspend(dev) spimem_flash_ll_suspend((spi_mem_dev_t*)dev)
#define spi_flash_ll_resume(dev) spimem_flash_ll_resume((spi_mem_dev_t*)dev)
#define spi_flash_ll_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) spimem_flash_ll_get_buffer_data((spi_mem_dev_t*)dev, buffer, read_len)
#define spi_flash_ll_set_buffer_data(dev, buffer, len) spimem_flash_ll_set_buffer_data((spi_mem_dev_t*)dev, buffer, len)
@ -103,6 +105,9 @@ typedef union {
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_auto_wait_idle_init(dev, auto_waiti) spimem_flash_ll_auto_wait_idle_init((spi_mem_dev_t*)dev, auto_waiti)
#define spi_flash_ll_auto_suspend_init(dev, auto_sus) spimem_flash_ll_auto_suspend_init((spi_mem_dev_t*)dev, auto_sus)
#define spi_flash_ll_sus_status(dev) spimem_flash_ll_sus_status((spi_mem_dev_t*)dev)
#endif

Wyświetl plik

@ -105,6 +105,67 @@ static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
{
dev->misc.auto_per = 0; // Must disable Hardware Auto-Resume (should not be enabled, ESP32-S2 has bugs).
dev->flash_sus_cmd.flash_per = 1;
while (dev->flash_sus_cmd.flash_per) { };
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{
dev->flash_sus_ctrl.flash_pes_command = 0x75; // Set auto suspend command, usually 0x75
dev->flash_sus_ctrl.flash_per_command = 0x7A; // Set auto resume command, usually 0x7A
// SET_PERI_REG_MASK(SPI_MEM_FLASH_SUS_CMD_REG(1), SPI_MEM_PES_PER_EN_M); // Only on S3 chip
// SET_PERI_REG_MASK(SPI_MEM_FLASH_SUS_CMD_REG(1), SPI_MEM_PESR_IDLE_EN_M); // MUST SET 1, to avoid missing Resume (Only on S3 chip)
dev->flash_sus_ctrl.flash_pes_en = auto_sus; // enable Flash Auto-Suspend.
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
{
dev->flash_waiti_ctrl.waiti_cmd = 0x05; // Set the command to send, to fetch flash status reg value.
dev->flash_waiti_ctrl.waiti_en = auto_waiti; // enable auto wait-idle function.
}
/**
* Return the suspend status of erase or program operations.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
static inline bool spimem_flash_ll_sus_status(const spi_mem_dev_t *dev)
{
return dev->sus_status.flash_sus;
}
/**
* Enable/disable write protection for the flash chip.
*

Wyświetl plik

@ -205,6 +205,13 @@ esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_inst_t *host, uint
*/
void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host);
/**
* Setup a auto-suspend mode.
*
* @param host The driver context.
*/
void spi_flash_hal_setup_auto_suspend_mode(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. *

Wyświetl plik

@ -177,6 +177,10 @@ struct spi_flash_host_driver_s {
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
/**
* Check the necessity of suspending erase/program operations.
*/
void (*check_suspend)(spi_flash_host_inst_t *host);
};
#ifdef __cplusplus

Wyświetl plik

@ -71,6 +71,17 @@ static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk
return apb_period_n / apbclk_n;
}
#ifdef CONFIG_SPI_FLASH_AUTO_SUSPEND
void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host)
{
mspi_auto_suspend_stub_install();
spi_flash_ll_auto_wait_idle_init(spi_flash_ll_get_hw(SPI_HOST), true);
spi_flash_ll_auto_suspend_init(spi_flash_ll_get_hw(SPI_HOST), true);
}
#endif // CONFIG_SPI_FLASH_AUTO_SUSPEND
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) && cfg->host_id == SPI1_HOST) {

Wyświetl plik

@ -23,6 +23,7 @@
#include "esp_heap_caps.h"
#include "hal/spi_types.h"
#include "driver/spi_common_internal.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash_internal.h"
#include "esp_rom_gpio.h"
#if CONFIG_IDF_TARGET_ESP32