Преглед изворни кода

light sleep: add cpu power down support for esp32c3

Li Shuai пре 5 година
родитељ
комит
f168ac3b39

+ 2 - 0
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)

+ 8 - 0
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;
 }
 

+ 8 - 0
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

+ 40 - 0
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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#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

+ 1 - 0
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;
 

+ 53 - 1
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

+ 2 - 1
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()
 

+ 16 - 0
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

+ 61 - 0
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);
+    }
+}

+ 8 - 0
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.
  */

+ 22 - 0
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))

+ 3 - 0
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)