Merge branch 'bugfix/further_fix_for_mspi_current_leakage_backport_v4.4' into 'release/v4.4'

system/sleep: further fix spi flash/ram current leakage(backport v4.4)

See merge request espressif/esp-idf!19212
This commit is contained in:
Jiang Jiang Jian 2022-08-04 14:46:56 +08:00
commit d16797b447
14 changed files with 252 additions and 50 deletions

View File

@ -26,7 +26,7 @@
extern "C" {
#endif
/// Type of hold a GPIO in low state
// Type of hold a GPIO in low state
typedef enum {
GPIO_LONG_HOLD = 1, /*!< The long hold GPIO */
GPIO_SHORT_HOLD = -1, /*!< The short hold GPIO */

View File

@ -22,13 +22,15 @@ menu "Hardware Settings"
config ESP_SLEEP_POWER_DOWN_FLASH
bool "Power down flash in light sleep when there is no SPIRAM"
depends on !SPIRAM
default y
default n
help
If enabled, chip will try to power down flash as part of esp_light_sleep_start(), which costs
more time when chip wakes up. Can only be enabled if there is no SPIRAM configured.
This option will in fact consider VDD_SDIO auto power value (ESP_PD_OPTION_AUTO) as OFF. Also, it is
possible to force a power domain to stay ON during light sleep by using esp_sleep_pd_config()
function.
This option will power down flash under a strict but relatively safe condition. Also, it is possible to
power down flash under a relaxed condition by using esp_sleep_pd_config() to set ESP_PD_DOMAIN_VDDSDIO
to ESP_PD_OPTION_OFF. It should be noted that there is a risk in powering down flash, you can refer
`ESP-IDF Programming Guide/API Reference/System API/Sleep Modes/Power-down of Flash` for more details.
config ESP_SLEEP_RTC_BUS_ISO_WORKAROUND
bool
@ -56,6 +58,7 @@ menu "Hardware Settings"
config ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND
bool "PSRAM leakage current workaround in light sleep"
depends on SPIRAM
default y
help
When the CS pin of SPIRAM is not pulled up, the sleep current will
increase during light sleep. If the CS pin of SPIRAM has an external
@ -64,11 +67,21 @@ menu "Hardware Settings"
config ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
bool "Flash leakage current workaround in light sleep"
default y
help
When the CS pin of Flash is not pulled up, the sleep current will
increase during light sleep. If the CS pin of Flash has an external
pull-up, you do not need to select this option, otherwise, you
should enable this option.
config ESP_SLEEP_MSPI_NEED_ALL_IO_PU
bool "All pins of mspi need pull up"
depends on ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND || ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
default y if IDF_TARGET_ESP32S3
help
To reduce leakage current, some types of SPI Flash/RAM only need to pull up the CS pin
during light sleep. But there are also some kinds of SPI Flash/RAM that need to pull up
all pins. It depends on the SPI Flash/RAM chip used.
endmenu
menu "RTC Clock Config"

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -19,15 +19,7 @@
#include "driver/gpio.h"
#include "esp_private/gpio.h"
#include "esp_private/sleep_gpio.h"
#include "bootloader_common.h"
#ifdef CONFIG_IDF_TARGET_ESP32
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#endif
#include "esp_private/spi_flash_os.h"
static const char *TAG = "sleep";
@ -55,24 +47,41 @@ IRAM_ATTR void gpio_sleep_mode_config_unapply(void)
void esp_sleep_config_gpio_isolate(void)
{
ESP_LOGI(TAG, "Configure to isolate all GPIO pins in sleep state");
ESP_EARLY_LOGI(TAG, "Configure to isolate all GPIO pins in sleep state");
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_GPIO(gpio_num)) {
gpio_sleep_set_direction(gpio_num, GPIO_MODE_DISABLE);
gpio_sleep_set_pull_mode(gpio_num, GPIO_FLOATING);
}
}
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
gpio_sleep_set_pull_mode(esp_spiram_get_cs_io(), GPIO_PULLUP_ONLY);
#endif
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS1), GPIO_PULLUP_ONLY);
#endif // CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
gpio_sleep_set_pull_mode(bootloader_flash_get_cs_io(), GPIO_PULLUP_ONLY);
#endif
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CS0), GPIO_PULLUP_ONLY);
#endif // CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
#if CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_CLK), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_Q), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_HD), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_WP), GPIO_PULLUP_ONLY);
#if CONFIG_SPIRAM_MODE_OCT || CONFIG_ESPTOOLPY_FLASHMODE_OPI
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_DQS), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D4), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D5), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D6), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_D7), GPIO_PULLUP_ONLY);
#endif // CONFIG_SPIRAM_MODE_OCT || CONFIG_ESPTOOLPY_FLASHMODE_OPI
#endif // CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU
}
void esp_sleep_enable_gpio_switch(bool enable)
{
ESP_LOGI(TAG, "%s automatic switching of GPIO sleep configuration", enable ? "Enable" : "Disable");
ESP_EARLY_LOGI(TAG, "%s automatic switching of GPIO sleep configuration", enable ? "Enable" : "Disable");
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_GPIO(gpio_num)) {
if (enable) {

View File

@ -11,12 +11,14 @@ if(target STREQUAL "linux")
"${target}/esp_rom_crc.c"
"${target}/esp_rom_md5.c"
"${target}/esp_rom_efuse.c")
list(APPEND include_dirs "${IDF_PATH}/tools/mocks/soc/include")
else()
list(APPEND include_dirs "${target}")
list(APPEND sources "patches/esp_rom_crc.c"
"patches/esp_rom_sys.c"
"patches/esp_rom_uart.c"
"patches/esp_rom_tjpgd.c")
"patches/esp_rom_tjpgd.c"
"patches/esp_rom_efuse.c")
list(APPEND private_required_comp soc hal)
endif()

View File

@ -16,6 +16,7 @@ PROVIDE ( esp_rom_gpio_connect_out_signal = gpio_matrix_out );
PROVIDE ( esp_rom_efuse_mac_address_crc8 = esp_crc8 );
PROVIDE ( esp_rom_efuse_get_flash_gpio_info = ets_efuse_get_spiconfig );
PROVIDE ( esp_rom_efuse_get_flash_wp_gpio = ets_efuse_get_wp_pad );
PROVIDE ( esp_rom_efuse_get_opiconfig = ets_efuse_get_opiconfig );
PROVIDE ( esp_rom_efuse_is_secure_boot_enabled = ets_efuse_secure_boot_enabled );
PROVIDE ( esp_rom_uart_flush_tx = uart_tx_flush );

View File

@ -1,16 +1,8 @@
// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@ -20,6 +12,7 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#define ESP_ROM_EFUSE_FLASH_DEFAULT_SPI (0)
#define ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI (1)
@ -56,6 +49,18 @@ uint32_t esp_rom_efuse_get_flash_gpio_info(void);
*/
uint32_t esp_rom_efuse_get_flash_wp_gpio(void);
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
/**
* @brief Read opi flash pads configuration from Efuse
*
* @return
* - 0 for default SPI pins.
* - Other values define a custom pin configuration mask. From the LSB, every 6 bits represent a GPIO number which stand for:
* DQS, D4, D5, D6, D7 accordingly.
*/
uint32_t esp_rom_efuse_get_opiconfig(void);
#endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
/**
* @brief Read eFuse to check whether secure boot has been enabled or not
*

View File

@ -1,16 +1,8 @@
// Copyright 2021 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.
// 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.
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_rom_efuse.h"
@ -49,6 +41,13 @@ uint32_t esp_rom_efuse_get_flash_wp_gpio(void)
return 0;
}
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
uint32_t esp_rom_efuse_get_opiconfig(void)
{
return 0;
}
#endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
bool esp_rom_efuse_is_secure_boot_enabled(void)
{
return false;

View File

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "soc/efuse_reg.h"
#if CONFIG_IDF_TARGET_ESP32S3
/**
* Since rom of esp32s3 does not export function ets_efuse_get_opiconfig,
* patch this function here.
*/
uint32_t esp_rom_efuse_get_opiconfig(void)
{
uint64_t spiconfig1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_2_REG, EFUSE_SPI_PAD_CONF_1);
uint64_t spiconfig2 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_SPI_PAD_CONF_2);
uint64_t opiconfig = (spiconfig2 << 12) | (spiconfig1 >> 20);
if (opiconfig == 0 || opiconfig == 0x3fffffffllu) {
return 0;
}
// MSBEFUSE_SPI_PAD_CONF_2(18bit) + EFUSE_SPI_PAD_CONF_1(32bit) + EFUSE_SPI_PAD_CONF_0(16bit) (LSB)
// [36:41] -- DQS
// [42:47] -- D4
// [48:53] -- D5
// [54:59] -- D6
// [60:65] -- D7
return opiconfig & 0x3fffffff;
}
#endif

View File

@ -15,6 +15,7 @@
#include <freertos/semphr.h>
#include <soc/soc.h>
#include <soc/soc_memory_layout.h>
#include "soc/io_mux_reg.h"
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_spi_flash.h"
@ -51,7 +52,18 @@
#include "esp_flash.h"
#include "esp_attr.h"
#include "bootloader_flash.h"
#include "bootloader_flash_config.h"
#include "esp_compiler.h"
#include "esp_rom_efuse.h"
#if CONFIG_SPIRAM
#ifdef CONFIG_IDF_TARGET_ESP32
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#endif
#endif
esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size);
@ -928,3 +940,84 @@ void IRAM_ATTR spi_flash_set_vendor_required_regs(void)
#endif // CONFIG_ESPTOOLPY_OCT_FLASH
}
#endif
static const uint8_t s_mspi_io_num_default[] = {
SPI_CLK_GPIO_NUM,
SPI_Q_GPIO_NUM,
SPI_D_GPIO_NUM,
SPI_CS0_GPIO_NUM,
SPI_HD_GPIO_NUM,
SPI_WP_GPIO_NUM,
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
SPI_DQS_GPIO_NUM,
SPI_D4_GPIO_NUM,
SPI_D5_GPIO_NUM,
SPI_D6_GPIO_NUM,
SPI_D7_GPIO_NUM
#endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
};
uint8_t esp_mspi_get_io(esp_mspi_io_t io)
{
#if CONFIG_SPIRAM
if (io == ESP_MSPI_IO_CS1) {
return esp_spiram_get_cs_io();
}
#endif
assert(io >= ESP_MSPI_IO_CLK);
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
assert(io <= ESP_MSPI_IO_D7);
#else
assert(io <= ESP_MSPI_IO_WP);
#endif
uint8_t mspi_io = 0;
uint32_t spiconfig = 0;
if (io == ESP_MSPI_IO_WP) {
/**
* wp pad is a bit special:
* 1. since 32's efuse does not have enough bits for wp pad, so wp pad config put in flash bin header
* 2. rom code take 0x3f as invalid wp pad num, but take 0 as other invalid mspi pads num
*/
#if CONFIG_IDF_TARGET_ESP32
return bootloader_flash_get_wp_pin();
#else
spiconfig = esp_rom_efuse_get_flash_wp_gpio();
return (spiconfig == 0x3f) ? s_mspi_io_num_default[io] : spiconfig & 0x3f;
#endif
}
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
spiconfig = (io < ESP_MSPI_IO_WP) ? esp_rom_efuse_get_flash_gpio_info() : esp_rom_efuse_get_opiconfig();
#else
spiconfig = esp_rom_efuse_get_flash_gpio_info();
#endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
mspi_io = s_mspi_io_num_default[io];
} else if (io < ESP_MSPI_IO_WP) {
/**
* [0 : 5] -- CLK
* [6 :11] -- Q(D1)
* [12:17] -- D(D0)
* [18:23] -- CS
* [24:29] -- HD(D3)
*/
mspi_io = (spiconfig >> io * 6) & 0x3f;
}
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
else {
/**
* [0 : 5] -- DQS
* [6 :11] -- D4
* [12:17] -- D5
* [18:23] -- D6
* [24:29] -- D7
*/
mspi_io = (spiconfig >> (io - ESP_MSPI_IO_DQS) * 6) & 0x3f;
}
#endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
return mspi_io;
}

View File

@ -34,11 +34,32 @@
#endif
#include "esp_flash.h"
#include "hal/spi_flash_hal.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
// Type of MSPI IO
typedef enum {
ESP_MSPI_IO_CLK = 0,
ESP_MSPI_IO_Q,
ESP_MSPI_IO_D,
ESP_MSPI_IO_CS0, /* cs for spi flash */
ESP_MSPI_IO_HD,
ESP_MSPI_IO_WP,
#if SOC_SPI_MEM_SUPPORT_OPI_MODE
ESP_MSPI_IO_DQS,
ESP_MSPI_IO_D4,
ESP_MSPI_IO_D5,
ESP_MSPI_IO_D6,
ESP_MSPI_IO_D7,
#endif // SOC_SPI_MEM_SUPPORT_OPI_MODE
#if CONFIG_SPIRAM
ESP_MSPI_IO_CS1 /* cs for spi ram */
#endif
} esp_mspi_io_t;
/**
* @brief To setup Flash chip
*/
@ -80,6 +101,15 @@ void spi_timing_psram_tuning(void);
*/
void esp_mspi_pin_init(void);
/**
* @brief Get the number of the GPIO corresponding to the given MSPI io
*
* @param[in] io MSPI io
*
* @return MSPI IO number
*/
uint8_t esp_mspi_get_io(esp_mspi_io_t io);
/**
* @brief Set SPI1 registers to make ROM functions work
* @note This function is used for setting SPI1 registers to the state that ROM SPI functions work

View File

@ -6,6 +6,7 @@ SOURCE_FILES := \
partition.c \
flash_ops.c \
esp32/flash_ops_esp32.c \
../esp_rom/linux/esp_rom_efuse.c \
) \
INCLUDE_DIRS := \

View File

@ -48,3 +48,8 @@ void spi_flash_enable_interrupts_caches_no_os(void)
{
return;
}
int bootloader_flash_get_wp_pin(void)
{
return 0;
}

View File

@ -171,7 +171,7 @@ By default, :cpp:func:`esp_deep_sleep_start` and :cpp:func:`esp_light_sleep_star
Power-down of Flash
-------------------
By default, to avoid potential issues, :cpp:func:`esp_deep_sleep_start` and :cpp:func:`esp_light_sleep_start` functions will **not** power down flash. To be more specific, it takes time to power down the flash and during this period the system may be woken up, which then actually powers up the flash before this flash could be powered down completely. As a result, there is a chance that the flash may not work properly.
By default, to avoid potential issues, :cpp:func:`esp_light_sleep_start` function will **not** power down flash. To be more specific, it takes time to power down the flash and during this period the system may be woken up, which then actually powers up the flash before this flash could be powered down completely. As a result, there is a chance that the flash may not work properly.
So, in theory, it's ok if you only wake up the system after the flash is completely powered down. However, in reality, the flash power-down period can be hard to predict (for example, this period can be much longer when you add filter capacitors to the flash's power supply circuit) and uncontrollable (for example, the asynchronous wake-up signals make the actual sleep time uncontrollable).
@ -192,7 +192,11 @@ However, for those who have fully understood the risk and are still willing to p
- Calling ``esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_OFF)`` powers down flash when the RTC timer is not enabled as a wakeup source **or** the sleep time is longer than the flash power-down period.
.. note::
ESP-IDF does not provide any mechanism that can power down the flash in all conditions.
.. list::
- ESP-IDF does not provide any mechanism that can power down the flash in all conditions when light sleep.
- :cpp:func:`esp_deep_sleep_start` function will force power down flash regardless of user configuration.
Entering light sleep
--------------------

View File

@ -0,0 +1,9 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* NOTE: this is not the original header file from the soc component. It is a stripped-down copy to support mocking.
*/