From f168ac3b3985348e893d94ac64cab66e79264cb9 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Thu, 24 Dec 2020 21:02:32 +0800 Subject: [PATCH] light sleep: add cpu power down support for esp32c3 --- components/esp_pm/linker.lf | 2 + components/esp_pm/pm_impl.c | 8 +++ components/esp_system/Kconfig | 8 +++ .../include/esp_private/sleep_modes.h | 40 ++++++++++++ components/esp_system/include/esp_sleep.h | 1 + components/esp_system/sleep_modes.c | 54 +++++++++++++++- components/hal/CMakeLists.txt | 3 +- .../hal/esp32c3/include/hal/rtc_cntl_ll.h | 16 +++++ components/hal/esp32c3/rtc_cntl_hal.c | 61 +++++++++++++++++++ components/hal/include/hal/rtc_hal.h | 8 +++ components/soc/esp32c3/include/soc/rtc_caps.h | 22 +++++++ components/soc/esp32c3/include/soc/soc_caps.h | 3 + 12 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 components/esp_system/include/esp_private/sleep_modes.h create mode 100644 components/hal/esp32c3/rtc_cntl_hal.c create mode 100644 components/soc/esp32c3/include/soc/rtc_caps.h diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index 67c8051b96..f332580978 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -72,3 +72,5 @@ entries: gpio_hal_workaround:gpio_hal_sleep_pupd_config_unapply (noflash) gpio_hal_workaround:gpio_hal_sleep_mode_setup_wrapper (noflash) gpio_hal_workaround:gpio_hal_fun_pupd_restore (noflash) + if PM_SLP_IRAM_OPT = y && ESP_SYSTEM_PM_POWER_DOWN_CPU = y: + rtc_cntl_hal:rtc_cntl_hal_enable_cpu_retention (noflash) diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index 6ad8703544..3b02cc64b0 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -60,6 +60,7 @@ #include "esp32c3/clk.h" #include "esp32c3/pm.h" #include "driver/gpio.h" +#include "esp_private/sleep_modes.h" #endif #define MHZ (1000000) @@ -303,6 +304,13 @@ esp_err_t esp_pm_configure(const void* vconfig) esp_sleep_gpio_status_switch_configure(config->light_sleep_enable); #endif +#if CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU && SOC_PM_SUPPORT_CPU_PD + esp_err_t ret = esp_sleep_cpu_pd_low_init(config->light_sleep_enable); + if (config->light_sleep_enable && ret != ESP_OK) { + ESP_LOGW(TAG, "Failed to enable CPU power down during light sleep."); + } +#endif + return ESP_OK; } diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 342b2c24ca..c31ab7c313 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -87,4 +87,12 @@ menu "ESP System Settings" If enabled, chip will try to power down flash at light sleep, which costs more time when chip wakes up. Only can be enabled if there is no SPIRAM configured. + config ESP_SYSTEM_PM_POWER_DOWN_CPU + bool "Power down CPU in light sleep" + depends on IDF_TARGET_ESP32C3 + default y + help + If enabled, the CPU will be powered down in light sleep. Enabling this option will consume + 1.68 KB of internal RAM and will reduce sleep current consumption by about 100 uA. + endmenu # ESP System Settings diff --git a/components/esp_system/include/esp_private/sleep_modes.h b/components/esp_system/include/esp_private/sleep_modes.h new file mode 100644 index 0000000000..e1584a8b57 --- /dev/null +++ b/components/esp_system/include/esp_private/sleep_modes.h @@ -0,0 +1,40 @@ +// Copyright 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. + +#pragma once + +#include +#include +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU +/** + * @brief CPU Power down low-level initialize + * + * @param enable enable or disable CPU power down during light sleep + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM not enough retention memory + */ +esp_err_t esp_sleep_cpu_pd_low_init(bool enable); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_system/include/esp_sleep.h b/components/esp_system/include/esp_sleep.h index 423bee51a1..6bc65b980a 100644 --- a/components/esp_system/include/esp_sleep.h +++ b/components/esp_system/include/esp_sleep.h @@ -42,6 +42,7 @@ typedef enum { ESP_PD_DOMAIN_RTC_SLOW_MEM, //!< RTC slow memory ESP_PD_DOMAIN_RTC_FAST_MEM, //!< RTC fast memory ESP_PD_DOMAIN_XTAL, //!< XTAL oscillator + ESP_PD_DOMAIN_CPU, //!< CPU core ESP_PD_DOMAIN_MAX //!< Number of domains } esp_sleep_pd_domain_t; diff --git a/components/esp_system/sleep_modes.c b/components/esp_system/sleep_modes.c index 4ecf1da2d7..1c846df1f3 100644 --- a/components/esp_system/sleep_modes.c +++ b/components/esp_system/sleep_modes.c @@ -70,6 +70,9 @@ #include "esp32s3/rom/cache.h" #include "esp32c3/rom/rtc.h" #include "soc/extmem_reg.h" +#include "esp_heap_caps.h" +#include "hal/rtc_hal.h" +#include "soc/rtc_caps.h" #endif // If light sleep time is less than that, don't power down flash @@ -141,10 +144,13 @@ typedef struct { uint32_t sleep_time_overhead_out; uint32_t rtc_clk_cal_period; uint64_t rtc_ticks_at_sleep_start; +#if SOC_PM_SUPPORT_CPU_PD + void *cpu_pd_mem; +#endif } sleep_config_t; static sleep_config_t s_config = { - .pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO }, + .pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO }, .ccount_ticks_record = 0, .sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US, .wakeup_triggers = 0 @@ -259,6 +265,32 @@ static void IRAM_ATTR resume_uarts(void) inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers); +#if SOC_PM_SUPPORT_CPU_PD +esp_err_t esp_sleep_cpu_pd_low_init(bool enable) +{ + if (enable) { + if (s_config.cpu_pd_mem == NULL) { + void *buf = heap_caps_aligned_alloc(RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN, + RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE, + MALLOC_CAP_RETENTION|MALLOC_CAP_DEFAULT); + if (buf) { + memset(buf, 0, RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE); + s_config.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf, + buf+RTC_HAL_DMA_LINK_NODE_SIZE, RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL); + } else { + return ESP_ERR_NO_MEM; + } + } + } else { + if (s_config.cpu_pd_mem) { + heap_caps_free(s_config.cpu_pd_mem); + s_config.cpu_pd_mem = NULL; + } + } + return ESP_OK; +} +#endif // SOC_PM_SUPPORT_CPU_PD + #if SOC_GPIO_SUPPORT_SLP_SWITCH #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL static inline void gpio_sleep_mode_config_apply(void) @@ -434,6 +466,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) s_config.ccount_ticks_record = cpu_ll_get_cycle_count(); } +#if SOC_PM_SUPPORT_CPU_PD + rtc_cntl_hal_disable_cpu_retention(); +#endif + #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL gpio_sleep_mode_config_unapply(); #endif @@ -591,6 +627,10 @@ esp_err_t esp_light_sleep_start(void) periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in); +#if SOC_PM_SUPPORT_CPU_PD + rtc_cntl_hal_enable_cpu_retention(s_config.cpu_pd_mem); +#endif + rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // Safety net: enable WDT in case exit from light sleep fails @@ -1046,6 +1086,12 @@ static uint32_t get_power_down_flags(void) #endif // SOC_TOUCH_PAD_WAKE_SUPPORTED } +#if !SOC_PM_SUPPORT_CPU_PD + if (s_config.pd_options[ESP_PD_DOMAIN_CPU] == ESP_PD_OPTION_AUTO) { + s_config.pd_options[ESP_PD_DOMAIN_CPU] = ESP_PD_OPTION_ON; + } +#endif + if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] == ESP_PD_OPTION_AUTO) { s_config.pd_options[ESP_PD_DOMAIN_XTAL] = ESP_PD_OPTION_OFF; } @@ -1071,6 +1117,12 @@ static uint32_t get_power_down_flags(void) pd_flags |= RTC_SLEEP_PD_RTC_PERIPH; } +#if SOC_PM_SUPPORT_CPU_PD + if (s_config.pd_options[ESP_PD_DOMAIN_CPU] != ESP_PD_OPTION_ON) { + pd_flags |= RTC_SLEEP_PD_CPU; + } +#endif + #ifdef CONFIG_IDF_TARGET_ESP32 pd_flags |= RTC_SLEEP_PD_XTAL; #endif diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 28e0bc3213..68e3cbfac6 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -92,7 +92,8 @@ if(NOT BOOTLOADER_BUILD) "esp32c3/systimer_hal.c" "esp32c3/hmac_hal.c" "spi_flash_hal_gpspi.c" - "spi_slave_hd_hal.c") + "spi_slave_hd_hal.c" + "esp32c3/rtc_cntl_hal.c") endif() endif() diff --git a/components/hal/esp32c3/include/hal/rtc_cntl_ll.h b/components/hal/esp32c3/include/hal/rtc_cntl_ll.h index 0e472eb80b..bcc8d0fcdb 100644 --- a/components/hal/esp32c3/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32c3/include/hal/rtc_cntl_ll.h @@ -17,6 +17,7 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" +#include "soc/apb_ctrl_reg.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,21 @@ static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void) REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); } +static inline void rtc_cntl_ll_enable_cpu_retention(uint32_t addr) +{ + /* write memory address to register */ + REG_SET_FIELD(APB_CTRL_RETENTION_CTRL_REG, APB_CTRL_RETENTION_LINK_ADDR, (uint32_t)addr); + /* Enable clock */ + REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN); + /* Enable retention when cpu sleep enable */ + REG_SET_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); +} + +static inline void rtc_cntl_ll_disable_cpu_retention(void) +{ + REG_CLR_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/rtc_cntl_hal.c b/components/hal/esp32c3/rtc_cntl_hal.c new file mode 100644 index 0000000000..0c8e1eb9a3 --- /dev/null +++ b/components/hal/esp32c3/rtc_cntl_hal.c @@ -0,0 +1,61 @@ +// Copyright 2015-2019 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. + +// The HAL layer for RTC CNTL (common part) + +#include "hal/rtc_hal.h" +#include "soc/soc_caps.h" +#include "esp32c3/rom/lldesc.h" +#include "esp_attr.h" + +#define RTC_CNTL_HAL_LINK_BUF_SIZE_MIN (RTC_CNTL_CPU_PD_DMA_BLOCK_SIZE) /* The minimum size of dma link buffer */ + +typedef struct rtc_cntl_link_buf_conf { + uint32_t cfg[4]; /* 4 word for dma link buffer configuration */ +} rtc_cntl_link_buf_conf_t; + +void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next) +{ + assert(elem != NULL); + assert(buff != NULL); + assert(size >= RTC_CNTL_HAL_LINK_BUF_SIZE_MIN); + + lldesc_t *plink = (lldesc_t *)elem; + + plink->eof = next ? 0 : 1; + plink->owner = 1; + plink->size = size >> 4; /* in unit of 16 bytes */ + plink->length = size >> 4; + plink->buf = buff; + plink->offset = 0; + plink->sosf = 0; + STAILQ_NEXT(plink, qe) = next; + return (void *)plink; +} + +void rtc_cntl_hal_enable_cpu_retention(void *addr) +{ + if (addr) { + lldesc_t *plink = (lldesc_t *)addr; + + /* dma link buffer configure */ + rtc_cntl_link_buf_conf_t *pbuf = (rtc_cntl_link_buf_conf_t *)plink->buf; + pbuf->cfg[0] = 0; + pbuf->cfg[1] = 0; + pbuf->cfg[2] = 0; + pbuf->cfg[3] = (uint32_t)-1; + + rtc_cntl_ll_enable_cpu_retention((uint32_t)addr); + } +} diff --git a/components/hal/include/hal/rtc_hal.h b/components/hal/include/hal/rtc_hal.h index 94c016c568..e4874ad168 100644 --- a/components/hal/include/hal/rtc_hal.h +++ b/components/hal/include/hal/rtc_hal.h @@ -18,6 +18,8 @@ #include "hal/rtc_io_ll.h" #include "hal/rtc_cntl_ll.h" +#define RTC_HAL_DMA_LINK_NODE_SIZE (16) + #define rtc_hal_ext1_get_wakeup_pins() rtc_cntl_ll_ext1_get_wakeup_pins() #define rtc_hal_ext1_set_wakeup_pins(mask, mode) rtc_cntl_ll_ext1_set_wakeup_pins(mask, mode) @@ -26,6 +28,12 @@ #define rtc_hal_set_wakeup_timer(ticks) rtc_cntl_ll_set_wakeup_timer(ticks) +void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next); + +void rtc_cntl_hal_enable_cpu_retention(void *addr); + +#define rtc_cntl_hal_disable_cpu_retention() rtc_cntl_ll_disable_cpu_retention() + /* * Enable wakeup from ULP coprocessor. */ diff --git a/components/soc/esp32c3/include/soc/rtc_caps.h b/components/soc/esp32c3/include/soc/rtc_caps.h new file mode 100644 index 0000000000..aa71a3ec2b --- /dev/null +++ b/components/soc/esp32c3/include/soc/rtc_caps.h @@ -0,0 +1,22 @@ +// Copyright 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. + +#pragma once + +#define RTC_CNTL_CPU_PD_DMA_BUS_WIDTH (128) +#define RTC_CNTL_CPU_PD_REG_FILE_NUM (108) +#define RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN (RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3) +#define RTC_CNTL_CPU_PD_DMA_BLOCK_SIZE (RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3) + +#define RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE (RTC_CNTL_CPU_PD_REG_FILE_NUM * (RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)) diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 0c063980b6..021f9b1438 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -44,6 +44,7 @@ #include "rmt_caps.h" #include "spi_caps.h" #include "uart_caps.h" +#include "rtc_caps.h" /*-------------------------- TOUCH SENSOR CAPS -------------------------------*/ #define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */ @@ -126,3 +127,5 @@ #define SOC_PM_SUPPORT_WIFI_WAKEUP (1) #define SOC_PM_SUPPORT_BT_WAKEUP (1) + +#define SOC_PM_SUPPORT_CPU_PD (1)