spi_flash: 2nd stage for supporting flash suspend. (1). Support more esp chips (2). Improve real-time performance (3). Making timing more stable (4) Add documents

This commit is contained in:
Cao Sen Miao 2023-05-11 20:10:30 +08:00
parent 476e50b026
commit ed96dadd06
34 changed files with 514 additions and 103 deletions

View File

@ -399,6 +399,16 @@ static inline void spi_flash_ll_set_cs_setup(spi_dev_t *dev, uint32_t cs_setup_t
dev->ctrl2.setup_time = cs_setup_time - 1; dev->ctrl2.setup_time = cs_setup_time - 1;
} }
/**
* @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on esp32
}
/** /**
* Get the spi flash source clock frequency. Used for calculating * Get the spi flash source clock frequency. Used for calculating
* the divider parameters. * the divider parameters.

View File

@ -149,6 +149,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on GPSPI
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -64,6 +64,7 @@ typedef union {
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) #define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@ -91,6 +92,7 @@ typedef union {
#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_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_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
#endif #endif

View File

@ -31,6 +31,7 @@ extern "C" {
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1) #define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
#define SPIMEM_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ (60) #define SPIMEM_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ (60)
#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS (0x1f)
typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
@ -207,6 +208,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
dev->flash_sus_ctrl.pesr_end_msk = sus_conf; dev->flash_sus_ctrl.pesr_end_msk = sus_conf;
} }
/**
* Configure the delay after Suspend/Resume
*
* @param dev Beginning address of the peripheral registers.
* @param dly_val delay time
*/
static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
{
dev->ctrl1.cs_hold_dly_res = dly_val;
dev->sus_status.flash_pes_dly_128 = 1;
dev->sus_status.flash_per_dly_128 = 1;
}
/**
* Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
*
* @param dev Beginning address of the peripheral registers.
* @param cs_hold_delay cs hold delay time
*/
static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
{
SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
}
/** /**
* Initialize auto wait idle mode * Initialize auto wait idle mode
* *
@ -232,6 +257,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
return dev->sus_status.flash_sus; return dev->sus_status.flash_sus;
} }
/**
* @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
*
* @param dev Beginning address of the peripheral registers.
* @param lock_time Lock delay time
*/
static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
{
dev->sus_status.spi0_lock_en = 1;
SPIMEM0.fsm.cspi_lock_delay_time = lock_time;
}
/**
* @brief Get tsus unit values in SPI_CLK cycles
*
* @param dev Beginning address of the peripheral registers.
* @return uint32_t tsus unit values
*/
static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
{
uint32_t tsus_unit = 0;
if (dev->sus_status.flash_pes_dly_128 == 1) {
tsus_unit = 128;
} else {
tsus_unit = 4;
}
return tsus_unit;
}
/** /**
* Enable/disable write protection for the flash chip. * Enable/disable write protection for the flash chip.
* *
@ -320,6 +374,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
* This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
{
dev->cmd.flash_pe = 1;
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -140,6 +140,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on GPSPI
}
/** /**
* Set HD pin high when flash work at spi mode. * Set HD pin high when flash work at spi mode.
* *

View File

@ -64,6 +64,7 @@ typedef union {
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) #define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@ -91,6 +92,7 @@ typedef union {
#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_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_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
#endif #endif

View File

@ -32,6 +32,8 @@ extern "C" {
#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL )) #define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1) #define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS (0x1f)
typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@ -207,6 +209,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf); HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
} }
/**
* Configure the delay after Suspend/Resume
*
* @param dev Beginning address of the peripheral registers.
* @param dly_val delay time
*/
static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
{
dev->ctrl1.cs_hold_dly_res = dly_val;
dev->sus_status.pes_dly_128 = 1;
dev->sus_status.per_dly_128 = 1;
}
/**
* Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
*
* @param dev Beginning address of the peripheral registers.
* @param cs_hold_delay cs hold delay time
*/
static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
{
SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
}
/** /**
* Initialize auto wait idle mode * Initialize auto wait idle mode
* *
@ -232,6 +258,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
return dev->sus_status.flash_sus; return dev->sus_status.flash_sus;
} }
/**
* @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
*
* @param dev Beginning address of the peripheral registers.
* @param lock_time Lock delay time
*/
static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
{
dev->sus_status.spi0_lock_en = 1;
SPIMEM0.fsm.cspi_lock_delay_time = lock_time;
}
/**
* @brief Get tsus unit values in SPI_CLK cycles
*
* @param dev Beginning address of the peripheral registers.
* @return uint32_t tsus unit values
*/
static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
{
uint32_t tsus_unit = 0;
if (dev->sus_status.pes_dly_128 == 1) {
tsus_unit = 128;
} else {
tsus_unit = 4;
}
return tsus_unit;
}
/** /**
* Enable/disable write protection for the flash chip. * Enable/disable write protection for the flash chip.
* *
@ -320,6 +375,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
* This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
{
dev->cmd.flash_pe = 1;
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -140,6 +140,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on GPSPI
}
/** /**
* Set HD pin high when flash work at spi mode. * Set HD pin high when flash work at spi mode.
* *

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -65,6 +65,7 @@ typedef union {
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) #define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_extra_address(dev, extra_addr) { /* Not supported on gpspi on ESP32-C6*/ } #define spi_flash_ll_set_extra_address(dev, extra_addr) { /* Not supported on gpspi on ESP32-C6*/ }
#define spi_flash_ll_set_pe_bit(dev) gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@ -92,6 +93,7 @@ typedef union {
#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_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_extra_address(dev, extra_addr) spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr) #define spi_flash_ll_set_extra_address(dev, extra_addr) spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr)
#define spi_flash_ll_set_pe_bit(dev) spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -33,6 +33,8 @@ extern "C" {
#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL )) #define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1) #define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS (0x1f)
typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@ -208,6 +210,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf); HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
} }
/**
* Configure the delay after Suspend/Resume
*
* @param dev Beginning address of the peripheral registers.
* @param dly_val delay time
*/
static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
{
dev->ctrl1.cs_hold_dly_res = dly_val;
dev->sus_status.flash_per_dly_128 = 1;
dev->sus_status.flash_pes_dly_128 = 1;
}
/**
* Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
*
* @param dev Beginning address of the peripheral registers.
* @param cs_hold_delay cs hold delay time
*/
static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
{
SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
}
/** /**
* Initialize auto wait idle mode * Initialize auto wait idle mode
* *
@ -233,6 +259,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
return dev->sus_status.flash_sus; return dev->sus_status.flash_sus;
} }
/**
* @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
*
* @param dev Beginning address of the peripheral registers.
* @param lock_time Lock delay time
*/
static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
{
dev->sus_status.spi0_lock_en = 1;
SPIMEM0.fsm.lock_delay_time = lock_time;
}
/**
* @brief Get tsus unit values in SPI_CLK cycles
*
* @param dev Beginning address of the peripheral registers.
* @return uint32_t tsus unit values
*/
static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
{
uint32_t tsus_unit = 0;
if (dev->sus_status.flash_pes_dly_128 == 1) {
tsus_unit = 128;
} else {
tsus_unit = 4;
}
return tsus_unit;
}
/** /**
* Enable/disable write protection for the flash chip. * Enable/disable write protection for the flash chip.
* *
@ -321,6 +376,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
* This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
{
dev->cmd.flash_pe = 1;
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -140,6 +140,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on GPSPI
}
/** /**
* Set HD pin high when flash work at spi mode. * Set HD pin high when flash work at spi mode.
* *

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -65,6 +65,7 @@ typedef union {
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) #define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_extra_address(dev, extra_addr) { /* Not supported on gpspi on ESP32-H2*/ } #define spi_flash_ll_set_extra_address(dev, extra_addr) { /* Not supported on gpspi on ESP32-H2*/ }
#define spi_flash_ll_set_pe_bit(dev) gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) #define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@ -92,6 +93,7 @@ typedef union {
#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_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_extra_address(dev, extra_addr) spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr) #define spi_flash_ll_set_extra_address(dev, extra_addr) spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr)
#define spi_flash_ll_set_pe_bit(dev) spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
#endif #endif

View File

@ -35,6 +35,8 @@ extern "C" {
#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL )) #define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1) #define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS (0x1f)
typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@ -210,6 +212,30 @@ static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint3
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf); HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
} }
/**
* Configure the delay after Suspend/Resume
*
* @param dev Beginning address of the peripheral registers.
* @param dly_val delay time
*/
static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
{
dev->ctrl1.cs_hold_dly_res = dly_val;
dev->sus_status.flash_per_dly_128 = 1;
dev->sus_status.flash_pes_dly_128 = 1;
}
/**
* Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
*
* @param dev Beginning address of the peripheral registers.
* @param cs_hold_delay cs hold delay time
*/
static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
{
SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
}
/** /**
* Initialize auto wait idle mode * Initialize auto wait idle mode
* *
@ -235,6 +261,35 @@ static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
return dev->sus_status.flash_sus; return dev->sus_status.flash_sus;
} }
/**
* @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
*
* @param dev Beginning address of the peripheral registers.
* @param lock_time Lock delay time
*/
static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
{
dev->sus_status.spi0_lock_en = 1;
SPIMEM0.fsm.lock_delay_time = lock_time;
}
/**
* @brief Get tsus unit values in SPI_CLK cycles
*
* @param dev Beginning address of the peripheral registers.
* @return uint32_t tsus unit values
*/
static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
{
uint32_t tsus_unit = 0;
if (dev->sus_status.flash_pes_dly_128 == 1) {
tsus_unit = 128;
} else {
tsus_unit = 4;
}
return tsus_unit;
}
/** /**
* Enable/disable write protection for the flash chip. * Enable/disable write protection for the flash chip.
* *
@ -323,6 +378,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
* This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
{
dev->cmd.flash_pe = 1;
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -134,6 +134,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on GPSPI
}
/** /**
* Set HD pin high when flash work at spi mode. * Set HD pin high when flash work at spi mode.
* *

View File

@ -65,6 +65,7 @@ typedef union {
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) #define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
#else #else
@ -94,6 +95,7 @@ typedef union {
#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_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_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
#endif #endif

View File

@ -316,6 +316,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
* This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
{
dev->cmd.flash_pe = 1;
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -145,6 +145,16 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_set_pe_bit(spi_dev_t *dev)
{
// Not supported on GPSPI
}
/** /**
* Set HD pin high when flash work at spi mode. * Set HD pin high when flash work at spi mode.
* *

View File

@ -63,6 +63,7 @@ typedef union {
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev) #define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) #define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) gpspi_flash_ll_set_pe_bit((spi_dev_t*)dev)
#else #else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) #define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
@ -91,6 +92,8 @@ typedef union {
#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_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_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) #define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time)
#define spi_flash_ll_set_pe_bit(dev) spimem_flash_ll_set_pe_bit((spi_mem_dev_t*)dev)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -32,6 +32,8 @@ extern "C" {
#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL )) #define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1) #define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
#define SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS (0x1f)
typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@ -120,6 +122,7 @@ static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus) static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{ {
dev->flash_sus_ctrl.flash_pes_en = auto_sus; // enable Flash Auto-Suspend. dev->flash_sus_ctrl.flash_pes_en = auto_sus; // enable Flash Auto-Suspend.
dev->flash_sus_cmd.pes_per_en = auto_sus;
} }
/** /**
@ -167,7 +170,7 @@ static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t
*/ */
static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd) static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
{ {
abort(); //Not support on esp32s3 //Not support on esp32s3
} }
/** /**
@ -201,7 +204,59 @@ static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool
*/ */
static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_mask) static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_mask)
{ {
abort();// Not supported on esp32s3 // Not supported on esp32s3
}
/**
* Configure the delay after Suspend/Resume
*
* @param dev Beginning address of the peripheral registers.
* @param dly_val delay time
*/
static inline void spimem_flash_ll_set_sus_delay(spi_mem_dev_t *dev, uint32_t dly_val)
{
dev->ctrl1.cs_hold_dly_res = dly_val;
dev->sus_status.flash_per_dly_256 = 1;
dev->sus_status.flash_pes_dly_256 = 1;
}
/**
* Configure the cs hold delay time(used to set the minimum CS high time tSHSL)
*
* @param dev Beginning address of the peripheral registers.
* @param cs_hold_delay cs hold delay time
*/
static inline void spimem_flash_set_cs_hold_delay(spi_mem_dev_t *dev, uint32_t cs_hold_delay)
{
SPIMEM0.ctrl2.cs_hold_delay = cs_hold_delay;
}
/**
* @brief Set lock for SPI0 so that spi0 can request new cache request after a cache transfer.
*
* @param dev Beginning address of the peripheral registers.
* @param lock_time Lock delay time
*/
static inline void spimem_flash_ll_sus_set_spi0_lock_trans(spi_mem_dev_t *dev, uint32_t lock_time)
{
// Not support on esp32s3
}
/**
* @brief Get tsus unit values in SPI_CLK cycles
*
* @param dev Beginning address of the peripheral registers.
* @return uint32_t tsus unit values
*/
static inline uint32_t spimem_flash_ll_get_tsus_unit_in_cycles(spi_mem_dev_t *dev)
{
uint32_t tsus_unit = 0;
if (dev->sus_status.flash_pes_dly_256 == 1) {
tsus_unit = 128;
} else {
tsus_unit = 4;
}
return tsus_unit;
} }
/** /**
@ -214,6 +269,8 @@ static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool
{ {
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); // Set the command to send, to fetch flash status reg value. HAL_FORCE_MODIFY_U32_REG_FIELD(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. dev->flash_waiti_ctrl.waiti_en = auto_waiti; // enable auto wait-idle function.
dev->flash_sus_cmd.flash_per_wait_en = 1;
dev->flash_sus_cmd.flash_pes_wait_en = 1;
} }
/** /**
@ -316,6 +373,17 @@ static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
dev->cmd.usr = 1; dev->cmd.usr = 1;
} }
/**
* In user mode, it is set to indicate that program/erase operation will be triggered.
* This function is combined with `spimem_flash_ll_user_start`. The pe_bit will be cleared automatically once the operation done.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_pe_bit(spi_mem_dev_t *dev)
{
dev->cmd.flash_pe = 1;
}
/** /**
* Check whether the host is idle to perform new commands. * Check whether the host is idle to perform new commands.
* *

View File

@ -47,8 +47,9 @@ typedef struct {
spi_flash_sus_cmd_conf sus_cfg; ///< To store suspend command/mask information. spi_flash_sus_cmd_conf sus_cfg; ///< To store suspend command/mask information.
uint32_t slicer_flags; /// Slicer flags for configuring how to slice data correctly while reading or writing. uint32_t slicer_flags; /// Slicer flags for configuring how to slice data correctly while reading or writing.
#define SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR BIT(0) ///< Slice data according to DTR mode, the address and length must be even (A0=0). #define SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR BIT(0) ///< Slice data according to DTR mode, the address and length must be even (A0=0).
int freq_mhz; /// Flash clock frequency.
} spi_flash_hal_context_t; } spi_flash_hal_context_t;
ESP_STATIC_ASSERT(sizeof(spi_flash_hal_context_t) == 40, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM"); ESP_STATIC_ASSERT(sizeof(spi_flash_hal_context_t) == 44, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// This struct provide MSPI Flash necessary timing related config, should be consistent with that in union in `spi_flash_hal_config_t`. /// This struct provide MSPI Flash necessary timing related config, should be consistent with that in union in `spi_flash_hal_config_t`.
typedef struct { typedef struct {

View File

@ -27,6 +27,7 @@ typedef struct {
#define SPI_FLASH_TRANS_FLAG_CMD16 BIT(0) ///< Send command of 16 bits #define SPI_FLASH_TRANS_FLAG_CMD16 BIT(0) ///< Send command of 16 bits
#define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO BIT(1) ///< Not applying the basic io mode configuration for this transaction #define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO BIT(1) ///< Not applying the basic io mode configuration for this transaction
#define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge #define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
#define SPI_FLASH_TRANS_FLAG_PE_CMD BIT(3) ///< Indicates that this transaction is to erase/program flash chip.
uint16_t command; ///< Command to send uint16_t command; ///< Command to send
uint8_t dummy_bitlen; ///< Basic dummy bits to use uint8_t dummy_bitlen; ///< Basic dummy bits to use
uint32_t io_mode; ///< Flash working mode when `SPI_FLASH_IGNORE_BASEIO` is specified. uint32_t io_mode; ///< Flash working mode when `SPI_FLASH_IGNORE_BASEIO` is specified.

View File

@ -103,6 +103,7 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
.cs_hold = cfg->cs_hold, .cs_hold = cfg->cs_hold,
.cs_setup = cfg->cs_setup, .cs_setup = cfg->cs_setup,
.base_io_mode = cfg->default_io_mode, .base_io_mode = cfg->default_io_mode,
.freq_mhz = cfg->freq_mhz,
}; };
#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
if (cfg->using_timing_tuning) { if (cfg->using_timing_tuning) {

View File

@ -170,6 +170,9 @@ esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_tr
spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len); spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len);
spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8); spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8);
if ((trans->flags & SPI_FLASH_TRANS_FLAG_PE_CMD) != 0) {
spi_flash_ll_set_pe_bit(dev);
}
spi_flash_ll_user_start(dev); spi_flash_ll_user_start(dev);
host->driver->poll_cmd_done(host); host->driver->poll_cmd_done(host);
if (trans->miso_len > 0) { if (trans->miso_len > 0) {

View File

@ -6,11 +6,14 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "hal/spi_flash_hal.h" #include "hal/spi_flash_hal.h"
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND #if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host); void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host);
void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host); void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host);
void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host); void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host);
void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host); void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host);
#define SPI_FLASH_TSUS_SAFE_VAL_US (30)
#define SPI_FLASH_TSHSL2_SAFE_VAL_NS (30)
#endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND #endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#ifndef CONFIG_SPI_FLASH_ROM_IMPL #ifndef CONFIG_SPI_FLASH_ROM_IMPL
@ -128,10 +131,12 @@ esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const sp
spi_mem_dev_t *dev = (spi_mem_dev_t *)spi_flash_ll_get_hw(SPI1_HOST); spi_mem_dev_t *dev = (spi_mem_dev_t *)spi_flash_ll_get_hw(SPI1_HOST);
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host; spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
memcpy(&(ctx->sus_cfg), sus_conf, sizeof(spi_flash_sus_cmd_conf)); memcpy(&(ctx->sus_cfg), sus_conf, sizeof(spi_flash_sus_cmd_conf));
spimem_flash_ll_set_read_sus_status(dev, sus_conf->sus_mask);
spimem_flash_ll_suspend_cmd_setup(dev, sus_conf->sus_cmd); spimem_flash_ll_suspend_cmd_setup(dev, sus_conf->sus_cmd);
spimem_flash_ll_resume_cmd_setup(dev, sus_conf->res_cmd); spimem_flash_ll_resume_cmd_setup(dev, sus_conf->res_cmd);
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
spimem_flash_ll_set_read_sus_status(dev, sus_conf->sus_mask);
spimem_flash_ll_rd_sus_cmd_setup(dev, sus_conf->cmd_rdsr); spimem_flash_ll_rd_sus_cmd_setup(dev, sus_conf->cmd_rdsr);
#endif // SOC_SPI_MEM_SUPPORT_CHECK_SUS
#endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND #endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
return ESP_OK; return ESP_OK;
} }
@ -140,8 +145,16 @@ esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const sp
void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host) void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host)
{ {
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST); spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI1_HOST);
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
spimem_flash_ll_auto_wait_idle_init(dev, true); spimem_flash_ll_auto_wait_idle_init(dev, true);
spimem_flash_ll_auto_suspend_init(dev, true); spimem_flash_ll_auto_suspend_init(dev, true);
// tsus = ceil(SPI_FLASH_TSUS_SAFE_VAL_US * ctx->freq_mhz / spimem_flash_ll_get_tsus_unit_in_cycles);
uint32_t tsus = (SPI_FLASH_TSUS_SAFE_VAL_US * ctx->freq_mhz / spimem_flash_ll_get_tsus_unit_in_cycles(dev)) + ((SPI_FLASH_TSUS_SAFE_VAL_US * ctx->freq_mhz) % spimem_flash_ll_get_tsus_unit_in_cycles(dev) != 0);
spimem_flash_ll_set_sus_delay(dev, tsus);
// tshsl2 = ceil(SPI_FLASH_TSHSL2_SAFE_VAL_NS * spimem_flash_ll_get_source_freq_mhz() * 0.001);
uint32_t tshsl2 = (SPI_FLASH_TSHSL2_SAFE_VAL_NS * spimem_flash_ll_get_source_freq_mhz() / 1000) + ((SPI_FLASH_TSHSL2_SAFE_VAL_NS * spimem_flash_ll_get_source_freq_mhz()) % 1000 != 0);
spimem_flash_set_cs_hold_delay(dev, tshsl2);
spimem_flash_ll_sus_set_spi0_lock_trans(dev, SPIMEM_FLASH_LL_SPI0_MAX_LOCK_VAL_MSPI_TICKS);
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS #if SOC_SPI_MEM_SUPPORT_CHECK_SUS
spimem_flash_ll_sus_check_sus_setup(dev, true); spimem_flash_ll_sus_check_sus_setup(dev, true);
#endif #endif

View File

@ -238,7 +238,14 @@ typedef volatile struct spi_mem_dev_s {
union { union {
struct { struct {
uint32_t flash_sus: 1; /*The status of flash suspend only used in SPI1.*/ uint32_t flash_sus: 1; /*The status of flash suspend only used in SPI1.*/
uint32_t reserved1: 31; /*reserved*/ uint32_t wait_pesr_cmd_2b:1;
uint32_t hpm_dly_128: 1;
uint32_t res_dly_128: 1;
uint32_t dp_dly_128: 1;
uint32_t per_dly_128: 1;
uint32_t pes_dly_128: 1;
uint32_t spi0_lock_en: 1;
uint32_t reserved1: 24; /*reserved*/
}; };
uint32_t val; uint32_t val;
} sus_status; } sus_status;

View File

@ -951,10 +951,6 @@ config SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE
bool bool
default y default y
config SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
bool
default y
config SOC_SPI_MEM_SUPPORT_SW_SUSPEND config SOC_SPI_MEM_SUPPORT_SW_SUSPEND
bool bool
default y default y

View File

@ -414,7 +414,6 @@
/*-------------------------- SPI MEM CAPS ---------------------------------------*/ /*-------------------------- SPI MEM CAPS ---------------------------------------*/
#define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1) #define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1) #define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE (1) #define SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE (1)
#define SOC_SPI_MEM_SUPPORT_WRAP (1) #define SOC_SPI_MEM_SUPPORT_WRAP (1)

View File

@ -11,3 +11,11 @@ components/spi_flash/test_apps/flash_encryption:
- if: IDF_TARGET in ["esp32c2", "esp32s2", "esp32c6", "esp32h2"] - if: IDF_TARGET in ["esp32c2", "esp32s2", "esp32c6", "esp32h2"]
temporary: true temporary: true
reason: No runners # IDF-5634 reason: No runners # IDF-5634
components/spi_flash/test_apps/flash_suspend:
disable:
- if: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND != 1
disable_test:
- if: IDF_TARGET != "esp32c3"
temporary: true
reason: lack of runners

View File

@ -147,17 +147,24 @@ menu "SPI Flash driver"
help help
Defines how many ticks will be before returning to continue a erasing. Defines how many ticks will be before returning to continue a erasing.
config SPI_FLASH_SUSPEND_QVL_SUPPORTED
# Internally usage
bool
default y if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
default n
config SPI_FLASH_AUTO_SUSPEND config SPI_FLASH_AUTO_SUSPEND
bool "Auto suspend long erase/write operations (READ DOCS FIRST)" bool "Auto suspend long erase/write operations (READ DOCS FIRST)"
default n default n
depends on IDF_TARGET_ESP32C3 && !SPI_FLASH_ROM_IMPL depends on SPI_FLASH_SUSPEND_QVL_SUPPORTED && !SPI_FLASH_ROM_IMPL
help help
This option is default n before ESP32-C3, because it needs bootloader support. This option is default n because it can't be used in every situation. You need to
evaluate this feature through suspend part in `SPI Flash API` document.
CAUTION: If you want to OTA to an app with this feature turned on, please make CAUTION: If you want to OTA to an app with this feature turned on, please make
sure the bootloader has the support for it. (later than IDF v4.3) sure the bootloader has the support for it. (later than IDF v4.3)
Auto-suspend feature only supported by XMC chip. Auto-suspend feature only supported by specific flash chips.
If you are using an official module, please contact Espressif Business support. If you are using an official module, please contact Espressif Business support.
Also reading auto suspend part in `SPI Flash API` document before you enable this function. Also reading auto suspend part in `SPI Flash API` document before you enable this function.

View File

@ -97,26 +97,7 @@ esp_flash_t *esp_flash_default_chip = NULL;
.input_delay_ns = 0,\ .input_delay_ns = 0,\
.cs_setup = 1,\ .cs_setup = 1,\
} }
#elif CONFIG_IDF_TARGET_ESP32S2 #else // Other target
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI1_HOST,\
.freq_mhz = DEFAULT_FLASH_SPEED, \
.cs_num = 0, \
.iomux = true, \
.input_delay_ns = 0,\
.cs_setup = 1,\
}
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/efuse.h"
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI1_HOST,\
.freq_mhz = DEFAULT_FLASH_SPEED, \
.cs_num = 0, \
.iomux = true, \
.input_delay_ns = 0,\
.cs_setup = 1,\
}
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
#if !CONFIG_SPI_FLASH_AUTO_SUSPEND #if !CONFIG_SPI_FLASH_AUTO_SUSPEND
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \ #define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI1_HOST,\ .host_id = SPI1_HOST,\
@ -137,7 +118,7 @@ esp_flash_t *esp_flash_default_chip = NULL;
.cs_setup = 1,\ .cs_setup = 1,\
} }
#endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND #endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
#endif #endif // Other target
static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux, int cs_id) static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux, int cs_id)
{ {

View File

@ -11,6 +11,7 @@
#include "spi_flash_chip_generic.h" #include "spi_flash_chip_generic.h"
#include "spi_flash_chip_gd.h" #include "spi_flash_chip_gd.h"
#include "spi_flash_defs.h" #include "spi_flash_defs.h"
#include "sdkconfig.h"
#define ADDR_32BIT(addr) (addr >= (1<<24)) #define ADDR_32BIT(addr) (addr >= (1<<24))
@ -33,6 +34,17 @@ spi_flash_caps_t spi_flash_chip_gd_get_caps(esp_flash_t *chip)
if ((chip->chip_id & 0xFF) >= 0x19) { if ((chip->chip_id & 0xFF) >= 0x19) {
caps_flags |= SPI_FLASH_CHIP_CAP_32MB_SUPPORT; caps_flags |= SPI_FLASH_CHIP_CAP_32MB_SUPPORT;
} }
#if CONFIG_SPI_FLASH_AUTO_SUSPEND
switch (chip->chip_id) {
/* The flash listed here can support suspend */
case 0xC84017:
case 0xC84018:
caps_flags |= SPI_FLASH_CHIP_CAP_SUSPEND;
break;
default:
break;
}
#endif
// flash-suspend is not supported // flash-suspend is not supported
// flash read unique id. // flash read unique id.
caps_flags |= SPI_FLASH_CHIP_CAP_UNIQUE_ID; caps_flags |= SPI_FLASH_CHIP_CAP_UNIQUE_ID;
@ -112,6 +124,18 @@ esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t*
} }
#endif //CONFIG_SPI_FLASH_ROM_IMPL #endif //CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t spi_flash_chip_gd_suspend_cmd_conf(esp_flash_t *chip)
{
spi_flash_sus_cmd_conf sus_conf = {
.sus_mask = 0x84,
.cmd_rdsr = CMD_RDSR2,
.sus_cmd = CMD_SUSPEND,
.res_cmd = CMD_RESUME,
};
return chip->host->driver->sus_setup(chip->host, &sus_conf);
}
static const char chip_name[] = "gd"; static const char chip_name[] = "gd";
// The issi chip can use the functions for generic chips except from set read mode and probe, // The issi chip can use the functions for generic chips except from set read mode and probe,
@ -148,7 +172,7 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.read_reg = spi_flash_chip_generic_read_reg, .read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield, .yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf, .sus_setup = spi_flash_chip_gd_suspend_cmd_conf,
.read_unique_id = spi_flash_chip_generic_read_unique_id, .read_unique_id = spi_flash_chip_generic_read_unique_id,
.get_chip_caps = spi_flash_chip_gd_get_caps, .get_chip_caps = spi_flash_chip_gd_get_caps,
.config_host_io_mode = spi_flash_chip_generic_config_host_io_mode, .config_host_io_mode = spi_flash_chip_generic_config_host_io_mode,

View File

@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// 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 <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -209,6 +201,7 @@ static esp_err_t spi_flash_command_winbond_program_4B(esp_flash_t *chip, const v
.address = address, .address = address,
.mosi_len = length, .mosi_len = length,
.mosi_data = buffer, .mosi_data = buffer,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
}; };
return chip->host->driver->common_command(chip->host, &t); return chip->host->driver->common_command(chip->host, &t);
} }
@ -220,6 +213,7 @@ esp_err_t spi_flash_command_winbond_erase_sector_4B(esp_flash_t *chip, uint32_t
.command = (addr_4b? CMD_SECTOR_ERASE_4B: CMD_SECTOR_ERASE), .command = (addr_4b? CMD_SECTOR_ERASE_4B: CMD_SECTOR_ERASE),
.address_bitlen = (addr_4b? 32: 24), .address_bitlen = (addr_4b? 32: 24),
.address = start_address, .address = start_address,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
}; };
return chip->host->driver->common_command(chip->host, &t); return chip->host->driver->common_command(chip->host, &t);
} }
@ -231,6 +225,7 @@ esp_err_t spi_flash_command_erase_block_4B(esp_flash_t *chip, uint32_t start_add
.command = (addr_4b? CMD_LARGE_BLOCK_ERASE_4B: CMD_LARGE_BLOCK_ERASE), .command = (addr_4b? CMD_LARGE_BLOCK_ERASE_4B: CMD_LARGE_BLOCK_ERASE),
.address_bitlen = (addr_4b? 32: 24), .address_bitlen = (addr_4b? 32: 24),
.address = start_address, .address = start_address,
.flags = SPI_FLASH_TRANS_FLAG_PE_CMD,
}; };
return chip->host->driver->common_command(chip->host, &t); return chip->host->driver->common_command(chip->host, &t);
} }

View File

@ -459,55 +459,6 @@ static void test_flash_erase_not_trigger_wdt(const esp_partition_t *part)
TEST_CASE_MULTI_FLASH_LONG("Test erasing flash chip not triggering WDT", test_flash_erase_not_trigger_wdt); TEST_CASE_MULTI_FLASH_LONG("Test erasing flash chip not triggering WDT", test_flash_erase_not_trigger_wdt);
#if CONFIG_SPI_FLASH_AUTO_SUSPEND
void esp_test_for_suspend(void)
{
/*clear content in cache*/
#if !CONFIG_IDF_TARGET_ESP32C3
Cache_Invalidate_DCache_All();
#endif
Cache_Invalidate_ICache_All();
ESP_LOGI(TAG, "suspend test begins:");
printf("run into test suspend function\n");
printf("print something when flash is erasing:\n");
printf("aaaaa bbbbb zzzzz fffff qqqqq ccccc\n");
}
static volatile bool task_erase_end, task_suspend_end = false;
void task_erase_large_region(void *arg)
{
esp_partition_t *part = (esp_partition_t *)arg;
test_erase_large_region(part);
task_erase_end = true;
vTaskDelete(NULL);
}
void task_request_suspend(void *arg)
{
vTaskDelay(2);
ESP_LOGI(TAG, "flash go into suspend");
esp_test_for_suspend();
task_suspend_end = true;
vTaskDelete(NULL);
}
static void test_flash_suspend_resume(const esp_partition_t* part)
{
xTaskCreatePinnedToCore(task_request_suspend, "suspend", 2048, (void *)"test_for_suspend", UNITY_FREERTOS_PRIORITY + 3, NULL, 0);
xTaskCreatePinnedToCore(task_erase_large_region, "test", 2048, (void *)part, UNITY_FREERTOS_PRIORITY + 2, NULL, 0);
while (!task_erase_end || !task_suspend_end) {
}
vTaskDelay(200);
}
TEST_CASE("SPI flash suspend and resume test", "[esp_flash][test_env=UT_T1_Flash_Suspend]")
{
flash_test_func(test_flash_suspend_resume, 1 /* first index reserved for main flash */ );
}
#endif //CONFIG_SPI_FLASH_AUTO_SUSPEND
static void test_write_protection(const esp_partition_t* part) static void test_write_protection(const esp_partition_t* part)
{ {
esp_flash_t* chip = part->flash_chip; esp_flash_t* chip = part->flash_chip;

View File

@ -999,7 +999,6 @@ components/spi_flash/include/spi_flash_chip_winbond.h
components/spi_flash/spi_flash_chip_boya.c components/spi_flash/spi_flash_chip_boya.c
components/spi_flash/spi_flash_chip_issi.c components/spi_flash/spi_flash_chip_issi.c
components/spi_flash/spi_flash_chip_mxic.c components/spi_flash/spi_flash_chip_mxic.c
components/spi_flash/spi_flash_chip_winbond.c
components/spi_flash/test/test_esp_flash.c components/spi_flash/test/test_esp_flash.c
components/spi_flash/test/test_flash_encryption.c components/spi_flash/test/test_flash_encryption.c
components/spi_flash/test/test_mmap.c components/spi_flash/test/test_mmap.c