kopia lustrzana https://github.com/espressif/esp-idf
spi_flash(esp32-s2): Add the workaround of a reboot issue when SPI HW suspend is enabled
rodzic
60e58eaddb
commit
1f37a5f162
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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. *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue