From e29c2c9a36e160c03e95f4f290cf78789099f168 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 28 Nov 2025 20:49:41 +0800 Subject: [PATCH] feat(spi_flash): add flash deep power down support in spi flash --- .../esp32/include/hal/spi_flash_ll.h | 22 ++++- .../esp32c2/include/hal/spi_flash_ll.h | 2 + .../esp32c2/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32c3/include/hal/spi_flash_ll.h | 2 + .../esp32c3/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32c5/include/hal/spi_flash_ll.h | 2 + .../esp32c5/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32c6/include/hal/spi_flash_ll.h | 2 + .../esp32c6/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32c61/include/hal/spi_flash_ll.h | 2 + .../esp32c61/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32h2/include/hal/spi_flash_ll.h | 2 + .../esp32h2/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32h21/include/hal/spi_flash_ll.h | 2 + .../esp32h21/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32h4/include/hal/spi_flash_ll.h | 2 + .../esp32h4/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32p4/include/hal/spi_flash_ll.h | 2 + .../esp32p4/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32s2/include/hal/spi_flash_ll.h | 2 + .../esp32s2/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32s3/include/hal/spi_flash_ll.h | 2 + .../esp32s3/include/hal/spimem_flash_ll.h | 20 ++++ .../esp32s31/include/hal/spi_flash_ll.h | 2 + .../esp32s31/include/hal/spimem_flash_ll.h | 20 ++++ .../esp_hal_mspi/include/hal/spi_flash_hal.h | 18 +++- components/esp_hal_mspi/spi_flash_hal_iram.c | 16 ++++ components/esp_hw_support/Kconfig | 45 +++++++++ components/spi_flash/CMakeLists.txt | 5 + .../include/esp_private/spi_flash_os.h | 30 +++++- components/spi_flash/linker.lf | 3 + components/spi_flash/spi_flash_dpd_enable.c | 91 +++++++++++++++++++ 32 files changed, 491 insertions(+), 3 deletions(-) create mode 100644 components/spi_flash/spi_flash_dpd_enable.c diff --git a/components/esp_hal_mspi/esp32/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32/include/hal/spi_flash_ll.h index 27f6e82ab3..7e06d9c0b2 100644 --- a/components/esp_hal_mspi/esp32/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32/include/hal/spi_flash_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -126,6 +126,26 @@ static inline void spi_flash_ll_set_write_protect(spi_dev_t *dev, bool wp) } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_enter_dpd(spi_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_exit_dpd(spi_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spi_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32c2/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32c2/include/hal/spi_flash_ll.h index cd5838d8cf..ae862d0986 100644 --- a/components/esp_hal_mspi/esp32c2/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32c2/include/hal/spi_flash_ll.h @@ -73,6 +73,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32c2/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32c2/include/hal/spimem_flash_ll.h index 8140fa4205..2916e288ad 100644 --- a/components/esp_hal_mspi/esp32c2/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32c2/include/hal/spimem_flash_ll.h @@ -315,6 +315,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32c3/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32c3/include/hal/spi_flash_ll.h index cd5838d8cf..ae862d0986 100644 --- a/components/esp_hal_mspi/esp32c3/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32c3/include/hal/spi_flash_ll.h @@ -73,6 +73,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32c3/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32c3/include/hal/spimem_flash_ll.h index 1fd64092e1..e18d532398 100644 --- a/components/esp_hal_mspi/esp32c3/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32c3/include/hal/spimem_flash_ll.h @@ -317,6 +317,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32c5/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32c5/include/hal/spi_flash_ll.h index a51dd6adf8..27bbb9e746 100644 --- a/components/esp_hal_mspi/esp32c5/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32c5/include/hal/spi_flash_ll.h @@ -78,6 +78,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32c5/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32c5/include/hal/spimem_flash_ll.h index afbb8ec472..09609913ec 100644 --- a/components/esp_hal_mspi/esp32c5/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32c5/include/hal/spimem_flash_ll.h @@ -338,6 +338,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32c6/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32c6/include/hal/spi_flash_ll.h index 21ba8889b3..c87ccd1a33 100644 --- a/components/esp_hal_mspi/esp32c6/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32c6/include/hal/spi_flash_ll.h @@ -75,6 +75,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32c6/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32c6/include/hal/spimem_flash_ll.h index 69d2475052..dbe784fd8f 100644 --- a/components/esp_hal_mspi/esp32c6/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32c6/include/hal/spimem_flash_ll.h @@ -318,6 +318,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32c61/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32c61/include/hal/spi_flash_ll.h index b97956ca11..2120509d04 100644 --- a/components/esp_hal_mspi/esp32c61/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32c61/include/hal/spi_flash_ll.h @@ -77,6 +77,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32c61/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32c61/include/hal/spimem_flash_ll.h index 892e08ca96..6462f381a4 100644 --- a/components/esp_hal_mspi/esp32c61/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32c61/include/hal/spimem_flash_ll.h @@ -332,6 +332,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32h2/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32h2/include/hal/spi_flash_ll.h index 0b7a6bb7b5..309405573c 100644 --- a/components/esp_hal_mspi/esp32h2/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32h2/include/hal/spi_flash_ll.h @@ -75,6 +75,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32h2/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32h2/include/hal/spimem_flash_ll.h index ac41f18087..493324b350 100644 --- a/components/esp_hal_mspi/esp32h2/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32h2/include/hal/spimem_flash_ll.h @@ -319,6 +319,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32h21/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32h21/include/hal/spi_flash_ll.h index 7abb40387f..ef812b4ac0 100644 --- a/components/esp_hal_mspi/esp32h21/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32h21/include/hal/spi_flash_ll.h @@ -71,6 +71,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32h21/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32h21/include/hal/spimem_flash_ll.h index be05c189cd..72d33c43f2 100644 --- a/components/esp_hal_mspi/esp32h21/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32h21/include/hal/spimem_flash_ll.h @@ -321,6 +321,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32h4/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32h4/include/hal/spi_flash_ll.h index 68ce940eba..84a826471d 100644 --- a/components/esp_hal_mspi/esp32h4/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32h4/include/hal/spi_flash_ll.h @@ -77,6 +77,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32h4/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32h4/include/hal/spimem_flash_ll.h index e1e7c416fd..2fd565004c 100644 --- a/components/esp_hal_mspi/esp32h4/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32h4/include/hal/spimem_flash_ll.h @@ -319,6 +319,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32p4/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32p4/include/hal/spi_flash_ll.h index 05a3f2bde4..5bf319bf67 100644 --- a/components/esp_hal_mspi/esp32p4/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32p4/include/hal/spi_flash_ll.h @@ -76,6 +76,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32p4/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32p4/include/hal/spimem_flash_ll.h index eba6f06368..46b3186e48 100644 --- a/components/esp_hal_mspi/esp32p4/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32p4/include/hal/spimem_flash_ll.h @@ -344,6 +344,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32s2/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32s2/include/hal/spi_flash_ll.h index 88861dd812..d05b0b445b 100644 --- a/components/esp_hal_mspi/esp32s2/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32s2/include/hal/spi_flash_ll.h @@ -76,6 +76,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32s2/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32s2/include/hal/spimem_flash_ll.h index 80ef0ecc1e..70d343a601 100644 --- a/components/esp_hal_mspi/esp32s2/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32s2/include/hal/spimem_flash_ll.h @@ -258,6 +258,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32s3/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32s3/include/hal/spi_flash_ll.h index 99d96cacf5..80b2fe6fe2 100644 --- a/components/esp_hal_mspi/esp32s3/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32s3/include/hal/spi_flash_ll.h @@ -74,6 +74,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32s3/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32s3/include/hal/spimem_flash_ll.h index 1f7eccfb0b..c071fd9413 100644 --- a/components/esp_hal_mspi/esp32s3/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32s3/include/hal/spimem_flash_ll.h @@ -320,6 +320,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/esp32s31/include/hal/spi_flash_ll.h b/components/esp_hal_mspi/esp32s31/include/hal/spi_flash_ll.h index c3125be500..35f2e1969b 100644 --- a/components/esp_hal_mspi/esp32s31/include/hal/spi_flash_ll.h +++ b/components/esp_hal_mspi/esp32s31/include/hal/spi_flash_ll.h @@ -76,6 +76,8 @@ typedef union { #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_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_enter_dpd(dev) spimem_flash_ll_enter_dpd((spi_mem_dev_t*)dev) +#define spi_flash_ll_exit_dpd(dev) spimem_flash_ll_exit_dpd((spi_mem_dev_t*)dev) #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) #define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) diff --git a/components/esp_hal_mspi/esp32s31/include/hal/spimem_flash_ll.h b/components/esp_hal_mspi/esp32s31/include/hal/spimem_flash_ll.h index 9d4fefb9b4..dad35b6684 100644 --- a/components/esp_hal_mspi/esp32s31/include/hal/spimem_flash_ll.h +++ b/components/esp_hal_mspi/esp32s31/include/hal/spimem_flash_ll.h @@ -329,6 +329,26 @@ static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp } } +/** + * Drive Flash into power down mode + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_enter_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_dp = 1; +} + +/** + * Releases Flash from the power-down state + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_exit_dpd(spi_mem_dev_t *dev) +{ + dev->cmd.flash_res = 1; +} + /** * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. * diff --git a/components/esp_hal_mspi/include/hal/spi_flash_hal.h b/components/esp_hal_mspi/include/hal/spi_flash_hal.h index c3c7897877..6b0ffd94b0 100644 --- a/components/esp_hal_mspi/include/hal/spi_flash_hal.h +++ b/components/esp_hal_mspi/include/hal/spi_flash_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -192,6 +192,22 @@ esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t */ esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp); +/** + * @brief Send the deep power down (b9h) command to the flash chip. + * + * @param host The driver context. + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_enter_dpd_mode(spi_flash_host_inst_t *host); + +/** + * @brief Send the release from deep power down (abh) command to the flash chip. + * + * @param host The driver context. + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_exit_dpd_mode(spi_flash_host_inst_t *host); + /** * Check whether the SPI host is idle and can perform other operations. * diff --git a/components/esp_hal_mspi/spi_flash_hal_iram.c b/components/esp_hal_mspi/spi_flash_hal_iram.c index 919644e381..4dcb77e0f8 100644 --- a/components/esp_hal_mspi/spi_flash_hal_iram.c +++ b/components/esp_hal_mspi/spi_flash_hal_iram.c @@ -88,6 +88,22 @@ esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp) return ESP_OK; } +esp_err_t spi_flash_hal_enter_dpd_mode(spi_flash_host_inst_t *host) +{ + spi_dev_t *dev = get_spi_dev(host); + spi_flash_ll_enter_dpd(dev); + host->driver->poll_cmd_done(host); + return ESP_OK; +} + +esp_err_t spi_flash_hal_exit_dpd_mode(spi_flash_host_inst_t *host) +{ + spi_dev_t *dev = get_spi_dev(host); + spi_flash_ll_exit_dpd(dev); + host->driver->poll_cmd_done(host); + return ESP_OK; +} + #else static inline spi_dev_t *get_spi_dev(spi_flash_host_inst_t *host) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 2d4cf55755..aa0258fc3f 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -214,6 +214,51 @@ menu "Hardware Settings" NOTE: Enabling these callbacks may change sleep duration calculations based on time spent in callback and hence it is highly recommended to keep them as short as possible. + + config ESP_SLEEP_SET_FLASH_DPD + bool "Set SPI flash to deep power-down mode in light sleep" + depends on (!APP_BUILD_TYPE_PURE_RAM_APP && !ESP_SLEEP_POWER_DOWN_FLASH && !SPI_FLASH_ROM_IMPL) + default y if (IDF_TARGET_ESP32H4 || IDF_TARGET_ESP32H21) + default n + help + Deep Power-Down mode is a power mode supported by most SPI Flash, SPI Flash has better power + consumption performance in this mode comparing to standby mode (hold CS). + Enabling this option will set the SPI Flash to deep power down mode during lightsleep to save power, + which will reduce the sleep current by about 10uA. And you can also use this option to reduce power + consumption when using PSRAM + + NOTE: We have conducted sufficient testing on ESP32H21, ESP32H4 and ESP32P4(less v3). If you plan to + use a customized flash chip, or if you are working with other ESP32-series chips, please make sure to + check the corresponding flash datasheet or consult us directly. This is to ensure that using the B9h + command to enter Deep Power-Down mode and ABh to exit Deep Power-Down mode will not introduce any + potential issues. + + config ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY + int "SPI Flash enter deep power-down time delay (in us)" + depends on ESP_SLEEP_SET_FLASH_DPD + default 20 + range 0 100 + help + When used to set the SPI Flash to enter the Deep Power-Down mode, the command is issued by driving + CS pin low, shifting the instruction code "B9H" and driving CS high, enter Deep Power-Down mode will + take the time duration of tDP before the supply current is reduced and Deep Power-down mode is + entered. The CS pin must keep high during the tDP time duration, adjust the value of this option to + configure the value of tDP, different types of flash require different tDP values, usually no more + than 20us, please refer to the datasheet of the used Flash to configure this option. + + config ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY + int "SPI Flash exit from deep power-down time delay (in us)" + depends on ESP_SLEEP_SET_FLASH_DPD + default 40 + range 0 100 + help + When used to exit the SPI Flash from the Deep Power-Down mode, the command is issued by driving the + CS pin low, shifting the instruction code "ABH" and driving CS high, release from Deep Power-Down will + take the time duration of tRES1 before the SPI FLASH will resume normal operation and other command are + accepted. The CS pin must keep high during the tRES1 time duration, adjust the value of this option + to configure the value of tRES1, different types of flash require different tRES1 values, usually no + more than 35us, please refer to the datasheet of the used Flash to configure this option. + endmenu menu "RTC Clock Config" diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 234e8ef966..dc8afb1ade 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -26,6 +26,11 @@ else() "spi_flash_hpm_enable.c") endif() + if(CONFIG_ESP_SLEEP_SET_FLASH_DPD) + list(APPEND srcs + "spi_flash_dpd_enable.c") + endif() + # New implementation after IDF v4.0 list(APPEND srcs "spi_flash_chip_drivers.c" diff --git a/components/spi_flash/include/esp_private/spi_flash_os.h b/components/spi_flash/include/esp_private/spi_flash_os.h index 22954c1783..89ac1e0c3d 100644 --- a/components/spi_flash/include/esp_private/spi_flash_os.h +++ b/components/spi_flash/include/esp_private/spi_flash_os.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -156,6 +156,34 @@ const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void); bool spi_flash_hpm_dummy_adjust(void); #endif //CONFIG_SPI_FLASH_HPM_ON +#if CONFIG_ESP_SLEEP_SET_FLASH_DPD + +/** + * @brief Get the duration of entering deep power-down mode. + * + * @return Entering deep power-down mode time(tDp), in microseconds. + */ +uint32_t spi_flash_dpd_get_enter_duration(void); + +/** + * @brief Get the duration of exiting deep power-down mode. + * + * @return Exiting deep power-down mode time(tRES1), in microseconds. + */ +uint32_t spi_flash_dpd_get_exit_duration(void); + +/** + * @brief Enable or disable SPI flash deep power-down mode. + * + * @param bool status. True: flash enable deep power-down mode. False: flash disable deep power-down mode. + * + * @note If using self-provided flash (not the chip’s factory-default flash), consult its datasheet to use this API safely. + * + * @return ESP_OK if success. + */ +esp_err_t spi_flash_enable_deep_power_down_mode(bool enable); +#endif + #if SOC_SPI_MEM_SUPPORT_WRAP /** * @brief set wrap size of flash diff --git a/components/spi_flash/linker.lf b/components/spi_flash/linker.lf index aa86cb039e..244b3f1bb4 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -73,6 +73,9 @@ entries: if SPI_FLASH_HPM_ON = y: spi_flash_hpm_enable (noflash) + if ESP_SLEEP_SET_FLASH_DPD = y: + spi_flash_dpd_enable (noflash) + [mapping:spi_flash_hal] archive: libesp_hal_mspi.a entries: diff --git a/components/spi_flash/spi_flash_dpd_enable.c b/components/spi_flash/spi_flash_dpd_enable.c new file mode 100644 index 0000000000..0eb7f47d5d --- /dev/null +++ b/components/spi_flash/spi_flash_dpd_enable.c @@ -0,0 +1,91 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "spi_flash_chip_generic.h" +#include "hal/spi_flash_hal.h" + +/******************************************************************************* + * Flash deep power-down mode. + * DPD: Deep power-down mode. + * TDP: CS high to deep power-down mode duration. + * TRES1: CS high to standby mode without ID read duration. + * + * Different flash chips might have different deep power-down strategy. + * 1. Most flash chips send B9H to enter DPD and send ABH to exist DPD. + * 2. Some flash chips send ABH followed by 3-dummy bytes to get device ID. + * 3. Some flash chips send B9H to enter PD(power-down) → send 79H to enter UDPD(ultra-deep power-down mode); send FFH to exit UDPD → send ABH to exit PD (ABH). + * 4. Some flash chips do nothing. + ******************************************************************************/ + +__attribute__((unused)) const static char *DPD_TAG = "flash DPD"; + +#ifdef CONFIG_ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY +#define SPI_FLASH_TDP_SAFE_VAL_US CONFIG_ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY +#else +#define SPI_FLASH_TDP_SAFE_VAL_US (25) +#endif + +#ifdef CONFIG_ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY +#define SPI_FLASH_TRES1_SAFE_VAL_US CONFIG_ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY +#else +#define SPI_FLASH_TRES1_SAFE_VAL_US (40) +#endif + +/* + * Note: This file should only be compiled when DPD_ON, which is only available when (!APP_BUILD_TYPE_PURE_RAM_APP && !ESP_SLEEP_POWER_DOWN_FLASH). + * However when DPD_ON, there are still some cases this file is not actually used: + * TODO: PM-623 + */ + +uint32_t spi_flash_dpd_get_enter_duration(void) +{ +#ifndef CONFIG_ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY + ESP_EARLY_LOGW(DPD_TAG, "No DPD enter delay value defined. Using default safe delay value. Verify with your flash datasheet."); +#endif + return SPI_FLASH_TDP_SAFE_VAL_US; +} + +uint32_t spi_flash_dpd_get_exit_duration(void) +{ +#ifndef CONFIG_ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY + ESP_EARLY_LOGW(DPD_TAG, "No DPD exit delay value defined. Using default safe delay value. Verify with your flash datasheet."); +#endif + return SPI_FLASH_TRES1_SAFE_VAL_US; +} + +static esp_err_t spi_flash_enter_dpd(void) +{ + esp_err_t ret = spi_flash_hal_enter_dpd_mode(esp_flash_default_chip->host); + esp_rom_delay_us(spi_flash_dpd_get_enter_duration()); + + return ret; +} + +static esp_err_t spi_flash_exit_dpd(void) +{ + esp_err_t ret = spi_flash_hal_exit_dpd_mode(esp_flash_default_chip->host); + esp_rom_delay_us(spi_flash_dpd_get_exit_duration()); + + return ret; +} + +esp_err_t spi_flash_enable_deep_power_down_mode(bool enable) +{ + esp_err_t ret = ESP_OK; + + if (enable) { + ret = spi_flash_enter_dpd(); + } else { + ret = spi_flash_exit_dpd(); + } + + return ret; +}