diff --git a/components/driver/test_apps/uart/main/CMakeLists.txt b/components/driver/test_apps/uart/main/CMakeLists.txt index 41dff71502..4f1cdd86bd 100644 --- a/components/driver/test_apps/uart/main/CMakeLists.txt +++ b/components/driver/test_apps/uart/main/CMakeLists.txt @@ -1,7 +1,19 @@ +set(srcs "test_app_main.c" + "test_uart.c") + +if(CONFIG_PM_ENABLE) + list(APPEND srcs "test_uart_auto_lightsleep.c") +endif() + +# Only if the target supports uart retention and the sdkconfig.ci.xxx contains at least PM_ENABLE=y +if(CONFIG_SOC_UART_SUPPORT_SLEEP_RETENTION AND CONFIG_PM_ENABLE) + list(APPEND srcs "test_uart_retention.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register( - SRCS "test_app_main.c" "test_uart.c" "test_uart_auto_lightsleep.c" + SRCS ${srcs} REQUIRES driver unity test_utils esp_pm PRIV_INCLUDE_DIRS . WHOLE_ARCHIVE diff --git a/components/driver/test_apps/uart/main/test_uart_auto_lightsleep.c b/components/driver/test_apps/uart/main/test_uart_auto_lightsleep.c index b409deafd8..308de2f4eb 100644 --- a/components/driver/test_apps/uart/main/test_uart_auto_lightsleep.c +++ b/components/driver/test_apps/uart/main/test_uart_auto_lightsleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,7 +10,6 @@ #include "esp_pm.h" #include "esp_log.h" #include "test_common.h" -#include "esp_private/sleep_cpu.h" //for sleep_cpu_configure #define UART_TAG "Uart" #define TEST_BUF_SIZE 256 @@ -34,7 +33,6 @@ #endif #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) -#if CONFIG_PM_ENABLE TEST_CASE("uart tx won't be blocked by auto light sleep", "[uart]") { @@ -82,10 +80,9 @@ TEST_CASE("uart tx won't be blocked by auto light sleep", "[uart]") uart_driver_delete(port_num); free(data); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP - //When PD_CPU enabled, retention may cause 14K memory leak. Workaround to release the memory - sleep_cpu_configure(false); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + pm_config.light_sleep_enable = false; + TEST_ESP_OK(esp_pm_configure(&pm_config)); #endif } -#endif // CONFIG_PM_ENABLE #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) diff --git a/components/driver/test_apps/uart/main/test_uart_retention.c b/components/driver/test_apps/uart/main/test_uart_retention.c new file mode 100644 index 0000000000..692d24f72f --- /dev/null +++ b/components/driver/test_apps/uart/main/test_uart_retention.c @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "unity.h" +#include "driver/uart.h" +#include "esp_pm.h" +#include "esp_private/sleep_cpu.h" +#include "esp_clk_tree.h" +#include "esp_sleep.h" + +// UART retention test only need to be done on HP UART + +static const uart_port_t uart_num = UART_NUM_1; + +static void uart_init(bool backup_before_sleep) +{ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags.backup_before_sleep = backup_before_sleep, + }; + + TEST_ESP_OK(uart_driver_install(uart_num, 256, 0, 20, NULL, 0)); + TEST_ESP_OK(uart_param_config(uart_num, &uart_config)); + TEST_ESP_OK(uart_set_loop_back(uart_num, true)); +} + +TEST_CASE("uart restored correctly after auto light sleep", "[uart][hp-uart-only]") +{ + // Configure dynamic frequency scaling: + // maximum and minimum frequencies are set in sdkconfig, + // automatic light sleep is enabled if tickless idle support is enabled. + uint32_t xtal_hz = 0; + esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz); + esp_pm_config_t pm_config = { + .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, + .min_freq_mhz = xtal_hz / 1000000, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true, +#endif + }; + TEST_ESP_OK(esp_pm_configure(&pm_config)); + + uart_init(true); + + // Ensure UART is fully idle before starting loopback RX/TX test + TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY)); + vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO + TEST_ESP_OK(uart_flush_input(uart_num)); + + for (int i = 0; i < 5; i++) { + char tx_data[20] = {0}; + char rx_data[20] = {0}; + int len = sprintf(tx_data, "Hello World %d!\n", i); + uart_write_bytes(uart_num, tx_data, len); + int size = 0; + // Polling to read the data back to avoid getting into auto light sleep + while (size < len) { + int bytes = uart_read_bytes(uart_num, (void *)((uint32_t)rx_data + size), 1, 0); + size += bytes; + } + rx_data[len] = '\0'; + printf("%s", rx_data); + TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0); + + vTaskDelay(pdMS_TO_TICKS(1000)); // auto light sleep + } + + TEST_ESP_OK(uart_driver_delete(uart_num)); + + pm_config.light_sleep_enable = false; + TEST_ESP_OK(esp_pm_configure(&pm_config)); +} + +TEST_CASE("uart restored correctly after manually enter light sleep", "[uart][hp-uart-only]") +{ + // Prepare a TOP PD sleep + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000)); + sleep_cpu_configure(true); + + uart_init(true); + + // Ensure UART is fully idle before starting loopback RX/TX test + TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY)); + vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO + TEST_ESP_OK(uart_flush_input(uart_num)); + + for (int i = 0; i < 5; i++) { + char tx_data[20] = {0}; + char rx_data[20] = {0}; + int len = sprintf(tx_data, "Hello World %d!\n", i); + uart_write_bytes(uart_num, tx_data, len); + int size = uart_read_bytes(uart_num, rx_data, len, pdMS_TO_TICKS(20)); + TEST_ASSERT_EQUAL(len, size); + rx_data[len] = '\0'; + printf("%s", rx_data); + TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0); + + printf("Going into sleep...\n"); + TEST_ESP_OK(esp_light_sleep_start()); + printf("Waked up!\n"); + } + + TEST_ESP_OK(uart_driver_delete(uart_num)); + TEST_ESP_OK(sleep_cpu_configure(false)); +} + +TEST_CASE("uart won't be powered down in light sleep if retention not created", "[uart][hp-uart-only]") +{ + // Prepare a TOP PD sleep + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000)); + sleep_cpu_configure(true); + + uart_init(false); // backup_before_sleep set to false, sleep retention module will be inited, but not created + + // Ensure UART is fully idle before starting loopback RX/TX test + TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY)); + vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO + TEST_ESP_OK(uart_flush_input(uart_num)); + + for (int i = 0; i < 3; i++) { + char tx_data[20] = {0}; + char rx_data[20] = {0}; + int len = sprintf(tx_data, "Hello World %d!\n", i); + uart_write_bytes(uart_num, tx_data, len); + int size = uart_read_bytes(uart_num, rx_data, len, pdMS_TO_TICKS(20)); + TEST_ASSERT_EQUAL(len, size); + rx_data[len] = '\0'; + printf("%s", rx_data); + TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0); + + printf("Going into sleep...\n"); + TEST_ESP_OK(esp_light_sleep_start()); // sleep without powering down TOP domain + printf("Waked up!\n"); + } + + TEST_ESP_OK(uart_driver_delete(uart_num)); + TEST_ESP_OK(sleep_cpu_configure(false)); +} diff --git a/components/driver/test_apps/uart/pytest_uart.py b/components/driver/test_apps/uart/pytest_uart.py index fd0b935f41..589798d0fd 100644 --- a/components/driver/test_apps/uart/pytest_uart.py +++ b/components/driver/test_apps/uart/pytest_uart.py @@ -26,12 +26,14 @@ input_argv = { def test_uart_single_dev(case_tester) -> None: # type: ignore dut = case_tester.dut chip_type = dut.app.target - for uart_port in input_argv.get(chip_type, []): - for case in case_tester.test_menu: - dut.serial.hard_reset() - dut._get_ready() - dut.confirm_write(case.index, expect_str=f'Running {case.name}...') - - dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) - dut.write(f'{uart_port}') - dut.expect_unity_test_output() + for case in case_tester.test_menu: + if 'hp-uart-only' not in case.groups: + for uart_port in input_argv.get(chip_type, []): + dut.serial.hard_reset() + dut._get_ready() + dut.confirm_write(case.index, expect_str=f'Running {case.name}...') + dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) + dut.write(f'{uart_port}') + dut.expect_unity_test_output() + else: + dut._run_normal_case(case, reset=True) diff --git a/components/driver/test_apps/uart/sdkconfig.ci.release b/components/driver/test_apps/uart/sdkconfig.ci.release index 673b6f8f74..a6be7c649b 100644 --- a/components/driver/test_apps/uart/sdkconfig.ci.release +++ b/components/driver/test_apps/uart/sdkconfig.ci.release @@ -1,5 +1,6 @@ CONFIG_PM_ENABLE=y CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/driver/uart/include/driver/uart.h b/components/driver/uart/include/driver/uart.h index 78adceebd6..1d2446afd5 100644 --- a/components/driver/uart/include/driver/uart.h +++ b/components/driver/uart/include/driver/uart.h @@ -49,6 +49,13 @@ typedef struct { lp_uart_sclk_t lp_source_clk; /*!< LP_UART source clock selection */ #endif }; + struct { +#if SOC_UART_SUPPORT_SLEEP_RETENTION + uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the HP UART registers before/after entering/exist sleep mode. + By this approach, the system can power off HP UART's power domain. + This can save power, but at the expense of more RAM being consumed */ +#endif + } flags; /*!< Configuration flags */ } uart_config_t; /** diff --git a/components/driver/uart/uart.c b/components/driver/uart/uart.c index ea374cf92b..8e7d1ce1af 100644 --- a/components/driver/uart/uart.c +++ b/components/driver/uart/uart.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include #include "esp_types.h" #include "esp_attr.h" #include "esp_intr_alloc.h" @@ -34,6 +35,7 @@ #include "esp_rom_gpio.h" #include "clk_ctrl_os.h" #include "esp_pm.h" +#include "esp_private/sleep_retention.h" #ifdef CONFIG_UART_ISR_IN_IRAM #define UART_ISR_ATTR IRAM_ATTR @@ -97,10 +99,11 @@ static const char *UART_TAG = "uart"; // Check actual UART mode set #define UART_IS_MODE_SET(uart_number, mode) ((p_uart_obj[uart_number]->uart_mode == mode)) -#define UART_CONTEX_INIT_DEF(uart_num) {\ - .hal.dev = UART_LL_GET_HW(uart_num),\ - INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)\ - .hw_enabled = false,\ +#define UART_CONTEX_INIT_DEF(uart_num) { \ + .port_id = uart_num, \ + .hal.dev = UART_LL_GET_HW(uart_num), \ + INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \ + .hw_enabled = false, \ } typedef struct { @@ -157,9 +160,15 @@ typedef struct { } uart_obj_t; typedef struct { + _lock_t mutex; /*!< Protect uart_module_enable, uart_module_disable, retention, etc. */ + uart_port_t port_id; uart_hal_context_t hal; /*!< UART hal context*/ DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) bool hw_enabled; +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + bool retention_link_inited; /*!< Mark whether the retention link is inited */ + bool retention_link_created; /*!< Mark whether the retention link is created */ +#endif } uart_context_t; static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; @@ -183,9 +192,17 @@ static uart_context_t uart_context[UART_NUM_MAX] = { static portMUX_TYPE uart_selectlock = portMUX_INITIALIZER_UNLOCKED; +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +#include "sleep_uart_retention_context.inc" + +const uart_reg_retention_info_t uart_reg_retention_info[SOC_UART_HP_NUM] = UART_REGS_RETENTION_INFO; + +static esp_err_t uart_create_sleep_retention_link_cb(void *arg); +#endif + static void uart_module_enable(uart_port_t uart_num) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_acquire(&(uart_context[uart_num].mutex)); if (uart_context[uart_num].hw_enabled != true) { if (uart_num < SOC_UART_HP_NUM) { HP_UART_BUS_CLK_ATOMIC() { @@ -196,6 +213,28 @@ static void uart_module_enable(uart_port_t uart_num) uart_ll_reset_register(uart_num); } } + +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Initialize sleep retention module for HP UART + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) { // Console uart retention has been taken care in sleep_sys_periph_stdout_console_uart_retention_init + assert(!uart_context[uart_num].retention_link_inited); + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = uart_create_sleep_retention_link_cb, + .arg = &uart_context[uart_num], + }, + }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), + }; + if (sleep_retention_module_init(module, &init_param) == ESP_OK) { + uart_context[uart_num].retention_link_inited = true; + } else { + ESP_LOGW(UART_TAG, "init sleep retention failed for uart%d, power domain may be turned off during sleep", uart_num); + } + } +#endif } #if (SOC_UART_LP_NUM >= 1) else { @@ -207,14 +246,24 @@ static void uart_module_enable(uart_port_t uart_num) #endif uart_context[uart_num].hw_enabled = true; } - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_release(&(uart_context[uart_num].mutex)); } static void uart_module_disable(uart_port_t uart_num) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_acquire(&(uart_context[uart_num].mutex)); if (uart_context[uart_num].hw_enabled != false) { if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) { +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Uninitialize sleep retention module for HP UART + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + assert(!uart_context[uart_num].retention_link_created); // HP UART sleep retention should have been freed at this moment + if (uart_context[uart_num].retention_link_inited) { + sleep_retention_module_deinit(module); + uart_context[uart_num].retention_link_inited = false; + } +#endif + HP_UART_BUS_CLK_ATOMIC() { uart_ll_enable_bus_clock(uart_num, false); } @@ -228,7 +277,7 @@ static void uart_module_disable(uart_port_t uart_num) #endif uart_context[uart_num].hw_enabled = false; } - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_release(&(uart_context[uart_num].mutex)); } esp_err_t uart_get_sclk_freq(uart_sclk_t sclk, uint32_t *out_freq_hz) @@ -801,6 +850,31 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf uart_module_enable(uart_num); +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Create sleep retention link if desired + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) { + _lock_acquire(&(uart_context[uart_num].mutex)); + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + if (uart_config->flags.backup_before_sleep && !uart_context[uart_num].retention_link_created) { + if (uart_context[uart_num].retention_link_inited) { + if (sleep_retention_module_allocate(module) == ESP_OK) { + uart_context[uart_num].retention_link_created = true; + } else { + // Even though the sleep retention module create failed, UART driver should still work, so just warning here + ESP_LOGW(UART_TAG, "create retention module failed, power domain can't turn off"); + } + } else { + ESP_LOGW(UART_TAG, "retention module not initialized first, unable to create retention module"); + } + } else if (!uart_config->flags.backup_before_sleep && uart_context[uart_num].retention_link_created) { + assert(uart_context[uart_num].retention_link_inited); + sleep_retention_module_free(module); + uart_context[uart_num].retention_link_created = false; + } + _lock_release(&(uart_context[uart_num].mutex)); + } +#endif + soc_module_clk_t uart_sclk_sel = 0; // initialize to an invalid module clock ID if (uart_num < SOC_UART_HP_NUM) { uart_sclk_sel = (soc_module_clk_t)((uart_config->source_clk) ? uart_config->source_clk : UART_SCLK_DEFAULT); // if no specifying the clock source (soc_module_clk_t starts from 1), then just use the default clock @@ -1713,6 +1787,20 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) periph_rtc_dig_clk8m_disable(); } #endif + +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Free sleep retention link for HP UART + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) { + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + _lock_acquire(&(uart_context[uart_num].mutex)); + if (uart_context[uart_num].retention_link_created) { + assert(uart_context[uart_num].retention_link_inited); + sleep_retention_module_free(module); + uart_context[uart_num].retention_link_created = false; + } + _lock_release(&(uart_context[uart_num].mutex)); + } +#endif uart_module_disable(uart_num); return ESP_OK; } @@ -1868,3 +1956,17 @@ void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout) p_uart_obj[uart_num]->rx_always_timeout_flg = false; } } + +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +static esp_err_t uart_create_sleep_retention_link_cb(void *arg) +{ + uart_context_t *group = (uart_context_t *)arg; + uart_port_t uart_num = group->port_id; + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + esp_err_t err = sleep_retention_entries_create(uart_reg_retention_info[uart_num].regdma_entry_array, + uart_reg_retention_info[uart_num].array_size, + REGDMA_LINK_PRI_7, module); + ESP_RETURN_ON_ERROR(err, UART_TAG, "create retention link failed"); + return ESP_OK; +} +#endif diff --git a/components/esp_hw_support/include/esp_private/sleep_retention.h b/components/esp_hw_support/include/esp_private/sleep_retention.h index 14a058b451..a55c301bdd 100644 --- a/components/esp_hw_support/include/esp_private/sleep_retention.h +++ b/components/esp_hw_support/include/esp_private/sleep_retention.h @@ -45,6 +45,8 @@ typedef enum sleep_retention_module { SLEEP_RETENTION_MODULE_GDMA_CH0 = 24, SLEEP_RETENTION_MODULE_GDMA_CH1 = 25, SLEEP_RETENTION_MODULE_GDMA_CH2 = 26, + SLEEP_RETENTION_MODULE_UART0 = 27, + SLEEP_RETENTION_MODULE_UART1 = 28, SLEEP_RETENTION_MODULE_MAX = 31 } sleep_retention_module_t; @@ -71,9 +73,23 @@ typedef enum sleep_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), SLEEP_RETENTION_MODULE_BM_GDMA_CH2 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH2), + SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), + SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), + SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } sleep_retention_module_bitmap_t; +#define TOP_DOMAIN_PERIPHERALS_BM (SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM \ + | SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM \ + | SLEEP_RETENTION_MODULE_BM_SYS_PERIPH \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH0 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH1 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH2 \ + | SLEEP_RETENTION_MODULE_BM_ADC \ + | SLEEP_RETENTION_MODULE_BM_UART0 \ + | SLEEP_RETENTION_MODULE_BM_UART1 \ + ) + typedef regdma_entry_buf_t sleep_retention_entries_t; typedef struct { diff --git a/components/esp_hw_support/port/esp32c6/private_include/sleep_gdma_retention_context.inc b/components/esp_hw_support/port/esp32c6/private_include/sleep_gdma_retention_context.inc index 6528598a4a..8787794129 100644 --- a/components/esp_hw_support/port/esp32c6/private_include/sleep_gdma_retention_context.inc +++ b/components/esp_hw_support/port/esp32c6/private_include/sleep_gdma_retention_context.inc @@ -63,7 +63,7 @@ static const sleep_retention_entries_config_t gdma_g0p2_regs_retention[] = { g0p2_regs_map0[0], g0p2_regs_map0[1], \ g0p2_regs_map0[2], g0p2_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MODEM_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MODEM_GDMA_LINK(0x01), \ G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ G0P2_RETENTION_REGS_CNT_1, 0, 0, \ g0p2_regs_map1[0], g0p2_regs_map1[1], \ diff --git a/components/esp_hw_support/port/esp32c6/private_include/sleep_uart_retention_context.inc b/components/esp_hw_support/port/esp32c6/private_include/sleep_uart_retention_context.inc new file mode 100644 index 0000000000..1b0e727da7 --- /dev/null +++ b/components/esp_hw_support/port/esp32c6/private_include/sleep_uart_retention_context.inc @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" +#include "soc/uart_reg.h" + +/** + * UART registers to be saved during sleep retention + * + * Reset TXFIFO and RXFIFO + * UART registers require set the reg_update bit to make the configuration take effect + * + * UART_INT_ENA_REG, UART_CLKDIV_SYNC_REG, UART_RX_FILT_REG, UART_CONF0_SYNC_REG, UART_CONF1_REG, + * UART_HWFC_CONF_SYNC_REG, UART_SLEEP_CONF0_REG, UART_SLEEP_CONF1_REG, UART_SLEEP_CONF2_REG, + * UART_SWFC_CONF0_SYNC_REG, UART_SWFC_CONF1_REG, UART_TXBRK_CONF_SYNC_REG, UART_IDLE_CONF_SYNC_REG, + * UART_RS485_CONF_SYNC_REG, UART_AT_CMD_PRECNT_SYNC_REG, UART_AT_CMD_POSTCNT_SYNC_REG, UART_AT_CMD_GAPTOUT_SYNC_REG, + * UART_AT_CMD_CHAR_SYNC_REG, UART_MEM_CONF_REG, UART_TOUT_CONF_SYNC_REG, UART_ID_REG + */ +#define UART_RETENTION_ADDR_MAP_REGS_CNT 21 +#define UART_RETENTION_REGS_BASE(i) UART_INT_ENA_REG(i) +static const uint32_t uart_regs_map[4] = {0x7fff6d, 0x10, 0x0, 0x0}; +#define UART_SLEEP_RETENTION_ENTRIES(uart_num) { \ + [0] = {.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_UART_LINK(0x00), \ + UART_RETENTION_REGS_BASE(uart_num), UART_RETENTION_REGS_BASE(uart_num), \ + UART_RETENTION_ADDR_MAP_REGS_CNT, 0, 0, \ + uart_regs_map[0], uart_regs_map[1], \ + uart_regs_map[2], uart_regs_map[3] \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = {.config = REGDMA_LINK_WRITE_INIT(REGDMA_UART_LINK(0x01), \ + UART_REG_UPDATE_REG(uart_num), UART_REG_UPDATE, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [2] = {.config = REGDMA_LINK_WAIT_INIT(REGDMA_UART_LINK(0x02), \ + UART_REG_UPDATE_REG(uart_num), 0x0, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const sleep_retention_entries_config_t uart0_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(0); +static const sleep_retention_entries_config_t uart1_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(1); + +typedef struct uart_reg_retention_info_t { + const sleep_retention_entries_config_t *regdma_entry_array; + uint32_t array_size; +} uart_reg_retention_info_t; + +#define UART_REGS_RETENTION_INFO { \ + [0] = { \ + .regdma_entry_array = uart0_regdma_entries, \ + .array_size = ARRAY_SIZE(uart0_regdma_entries), \ + }, \ + [1] = { \ + .regdma_entry_array = uart1_regdma_entries, \ + .array_size = ARRAY_SIZE(uart1_regdma_entries), \ + }, \ +}; diff --git a/components/esp_hw_support/port/esp32h2/private_include/sleep_gdma_retention_context.inc b/components/esp_hw_support/port/esp32h2/private_include/sleep_gdma_retention_context.inc index 6528598a4a..8787794129 100644 --- a/components/esp_hw_support/port/esp32h2/private_include/sleep_gdma_retention_context.inc +++ b/components/esp_hw_support/port/esp32h2/private_include/sleep_gdma_retention_context.inc @@ -63,7 +63,7 @@ static const sleep_retention_entries_config_t gdma_g0p2_regs_retention[] = { g0p2_regs_map0[0], g0p2_regs_map0[1], \ g0p2_regs_map0[2], g0p2_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MODEM_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MODEM_GDMA_LINK(0x01), \ G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ G0P2_RETENTION_REGS_CNT_1, 0, 0, \ g0p2_regs_map1[0], g0p2_regs_map1[1], \ diff --git a/components/esp_hw_support/port/esp32h2/private_include/sleep_uart_retention_context.inc b/components/esp_hw_support/port/esp32h2/private_include/sleep_uart_retention_context.inc new file mode 100644 index 0000000000..1b0e727da7 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/sleep_uart_retention_context.inc @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" +#include "soc/uart_reg.h" + +/** + * UART registers to be saved during sleep retention + * + * Reset TXFIFO and RXFIFO + * UART registers require set the reg_update bit to make the configuration take effect + * + * UART_INT_ENA_REG, UART_CLKDIV_SYNC_REG, UART_RX_FILT_REG, UART_CONF0_SYNC_REG, UART_CONF1_REG, + * UART_HWFC_CONF_SYNC_REG, UART_SLEEP_CONF0_REG, UART_SLEEP_CONF1_REG, UART_SLEEP_CONF2_REG, + * UART_SWFC_CONF0_SYNC_REG, UART_SWFC_CONF1_REG, UART_TXBRK_CONF_SYNC_REG, UART_IDLE_CONF_SYNC_REG, + * UART_RS485_CONF_SYNC_REG, UART_AT_CMD_PRECNT_SYNC_REG, UART_AT_CMD_POSTCNT_SYNC_REG, UART_AT_CMD_GAPTOUT_SYNC_REG, + * UART_AT_CMD_CHAR_SYNC_REG, UART_MEM_CONF_REG, UART_TOUT_CONF_SYNC_REG, UART_ID_REG + */ +#define UART_RETENTION_ADDR_MAP_REGS_CNT 21 +#define UART_RETENTION_REGS_BASE(i) UART_INT_ENA_REG(i) +static const uint32_t uart_regs_map[4] = {0x7fff6d, 0x10, 0x0, 0x0}; +#define UART_SLEEP_RETENTION_ENTRIES(uart_num) { \ + [0] = {.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_UART_LINK(0x00), \ + UART_RETENTION_REGS_BASE(uart_num), UART_RETENTION_REGS_BASE(uart_num), \ + UART_RETENTION_ADDR_MAP_REGS_CNT, 0, 0, \ + uart_regs_map[0], uart_regs_map[1], \ + uart_regs_map[2], uart_regs_map[3] \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = {.config = REGDMA_LINK_WRITE_INIT(REGDMA_UART_LINK(0x01), \ + UART_REG_UPDATE_REG(uart_num), UART_REG_UPDATE, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [2] = {.config = REGDMA_LINK_WAIT_INIT(REGDMA_UART_LINK(0x02), \ + UART_REG_UPDATE_REG(uart_num), 0x0, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const sleep_retention_entries_config_t uart0_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(0); +static const sleep_retention_entries_config_t uart1_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(1); + +typedef struct uart_reg_retention_info_t { + const sleep_retention_entries_config_t *regdma_entry_array; + uint32_t array_size; +} uart_reg_retention_info_t; + +#define UART_REGS_RETENTION_INFO { \ + [0] = { \ + .regdma_entry_array = uart0_regdma_entries, \ + .array_size = ARRAY_SIZE(uart0_regdma_entries), \ + }, \ + [1] = { \ + .regdma_entry_array = uart1_regdma_entries, \ + .array_size = ARRAY_SIZE(uart1_regdma_entries), \ + }, \ +}; diff --git a/components/esp_hw_support/sleep_cpu.c b/components/esp_hw_support/sleep_cpu.c index f77c4e336c..f2f7ad40e7 100644 --- a/components/esp_hw_support/sleep_cpu.c +++ b/components/esp_hw_support/sleep_cpu.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ #include "esp_check.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" +#include "esp_rom_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" @@ -654,12 +654,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t * #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - *(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size); + *(frame_crc_ptr) = esp_rom_crc32_le(0, (void *)frame_ptr, frame_check_size); } static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ + if(*(frame_crc_ptr) != esp_rom_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ // resume uarts for (int i = 0; i < SOC_UART_NUM; ++i) { #ifndef CONFIG_IDF_TARGET_ESP32 diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 3e4cd0ef7f..6ac25e06a1 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -18,7 +18,6 @@ #include "esp_private/sleep_retention.h" #include "esp_regdma.h" -#include "soc/uart_reg.h" #include "soc/systimer_reg.h" #include "soc/timer_group_reg.h" #include "soc/spi_mem_reg.h" @@ -84,22 +83,21 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_tee_apm_retention_init return ESP_OK; } -static __attribute__((unused)) esp_err_t sleep_sys_periph_uart0_retention_init(void *arg) +#if CONFIG_ESP_CONSOLE_UART +#include "sleep_uart_retention_context.inc" + +const uart_reg_retention_info_t uart_regs_retention[SOC_UART_HP_NUM] = UART_REGS_RETENTION_INFO; + +static __attribute__((unused)) esp_err_t sleep_sys_periph_stdout_console_uart_retention_init(void *arg) { - #define N_REGS_UART() (((UART_ID_REG(0) - UART_INT_RAW_REG(0)) / 4) + 1) - - const static sleep_retention_entries_config_t uart_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), UART_INT_RAW_REG(0), UART_INT_RAW_REG(0), N_REGS_UART(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* uart */ - /* Note: uart register should set update reg to make the configuration take effect */ - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_UART_LINK(0x01), UART_REG_UPDATE_REG(0), UART_REG_UPDATE, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_UART_LINK(0x02), UART_REG_UPDATE_REG(0), 0x0, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } - }; - - esp_err_t err = sleep_retention_entries_create(uart_regs_retention, ARRAY_SIZE(uart_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_SYS_PERIPH); + esp_err_t err = sleep_retention_entries_create(uart_regs_retention[CONFIG_ESP_CONSOLE_UART_NUM].regdma_entry_array, + uart_regs_retention[CONFIG_ESP_CONSOLE_UART_NUM].array_size, + REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_SYS_PERIPH); ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "UART"); - ESP_LOGD(TAG, "UART sleep retention initialization"); + ESP_LOGD(TAG, "stdout console UART sleep retention initialization"); return ESP_OK; } +#endif static __attribute__((unused)) esp_err_t sleep_sys_periph_tg0_retention_init(void *arg) { @@ -229,8 +227,10 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_retention_init(void *a if(err) goto error; err = sleep_sys_periph_tee_apm_retention_init(arg); if(err) goto error; - err = sleep_sys_periph_uart0_retention_init(arg); +#if CONFIG_ESP_CONSOLE_UART + err = sleep_sys_periph_stdout_console_uart_retention_init(arg); if(err) goto error; +#endif err = sleep_sys_periph_tg0_retention_init(arg); if(err) goto error; err = sleep_sys_periph_iomux_retention_init(arg); @@ -248,9 +248,7 @@ bool peripheral_domain_pd_allowed(void) #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP const uint32_t inited_modules = sleep_retention_get_inited_modules(); const uint32_t created_modules = sleep_retention_get_created_modules(); - const uint32_t mask = (const uint32_t) (BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH)); - - return ((inited_modules & mask) == (created_modules & mask)); + return (((inited_modules ^ created_modules) & TOP_DOMAIN_PERIPHERALS_BM) == 0); #else return false; #endif diff --git a/components/hal/esp32c6/include/hal/gpio_ll.h b/components/hal/esp32c6/include/hal/gpio_ll.h index 5bd7ea1178..e1a1cb9dea 100644 --- a/components/hal/esp32c6/include/hal/gpio_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_ll.h @@ -395,6 +395,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 |= GPIO_HOLD_MASK[gpio_num]; @@ -406,6 +407,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 &= ~GPIO_HOLD_MASK[gpio_num]; diff --git a/components/hal/esp32c6/include/hal/uart_ll.h b/components/hal/esp32c6/include/hal/uart_ll.h index 490924e602..6d2f3cda85 100644 --- a/components/hal/esp32c6/include/hal/uart_ll.h +++ b/components/hal/esp32c6/include/hal/uart_ll.h @@ -61,6 +61,10 @@ extern "C" { #define UART_LL_PCR_REG_GET(hw, reg_suffix, field_suffix) \ (((hw) == &UART0) ? PCR.uart0_##reg_suffix.uart0_##field_suffix : PCR.uart1_##reg_suffix.uart1_##field_suffix) +// UART sleep retention module +#define UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num) ((uart_num == UART_NUM_0) ? SLEEP_RETENTION_MODULE_UART0 : \ + (uart_num == UART_NUM_1) ? SLEEP_RETENTION_MODULE_UART1 : -1) + // Define UART interrupts typedef enum { UART_INTR_RXFIFO_FULL = (0x1 << 0), diff --git a/components/hal/esp32h2/include/hal/gpio_ll.h b/components/hal/esp32h2/include/hal/gpio_ll.h index df08c857be..7efdaac227 100644 --- a/components/hal/esp32h2/include/hal/gpio_ll.h +++ b/components/hal/esp32h2/include/hal/gpio_ll.h @@ -438,6 +438,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_ * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 |= GPIO_HOLD_MASK[gpio_num]; @@ -449,6 +450,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 &= ~GPIO_HOLD_MASK[gpio_num]; diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index 496fac1b37..ff9ca26655 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -57,6 +57,10 @@ extern "C" { #define UART_LL_PCR_REG_GET(hw, reg_suffix, field_suffix) \ (((hw) == &UART0) ? PCR.uart0_##reg_suffix.uart0_##field_suffix : PCR.uart1_##reg_suffix.uart1_##field_suffix) +// UART sleep retention module +#define UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num) ((uart_num == UART_NUM_0) ? SLEEP_RETENTION_MODULE_UART0 : \ + (uart_num == UART_NUM_1) ? SLEEP_RETENTION_MODULE_UART1 : -1) + // Define UART interrupts typedef enum { UART_INTR_RXFIFO_FULL = (0x1 << 0), diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index b3c41a5faa..c07de91ebe 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -472,6 +472,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { uint64_t bit_mask = 1ULL << gpio_num; @@ -497,6 +498,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { uint64_t bit_mask = 1ULL << gpio_num; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index e423abc8a9..cdbea17e83 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1175,6 +1175,10 @@ config SOC_UART_HAS_LP_UART bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index dc730f5755..5399788d2b 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -476,6 +476,7 @@ #define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */ #define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_HAS_LP_UART (1) /*!< Support LP UART */ +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index cf907411a4..03c34002f2 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1163,6 +1163,10 @@ config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_COEX_HW_PTI bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 584ad8c99a..4c3273d81b 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -475,6 +475,8 @@ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ + // TODO: IDF-5679 (Copy from esp32c6, need check) /*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/ #define SOC_COEX_HW_PTI (1) diff --git a/docs/en/api-reference/peripherals/uart.rst b/docs/en/api-reference/peripherals/uart.rst index fe9afb589c..564a57f487 100644 --- a/docs/en/api-reference/peripherals/uart.rst +++ b/docs/en/api-reference/peripherals/uart.rst @@ -66,6 +66,10 @@ Call the function :cpp:func:`uart_param_config` and pass to it a :cpp:type:`uart For more information on how to configure the hardware flow control options, please refer to :example:`peripherals/uart/uart_echo`. +.. only:: SOC_UART_SUPPORT_SLEEP_RETENTION + + Additionally, :cpp:member:`uart_config_t::backup_before_sleep` can be set to enable the backup of the UART configuration registers before entering sleep and restore these registers after exiting sleep. This allows the UART to continue working properly after waking up even when the UART module power domain is entirely off during sleep. This option implies an balance between power consumption and memory usage. If the power consumption is not a concern, you can disable this option to save memory. + Multiple Steps """""""""""""" diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index c281aa25ae..566f373f95 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -136,7 +136,7 @@ Light-sleep Peripheral Power Down - INT_MTX - TEE/APM - IO_MUX / GPIO - - UART0 + - UART0/1 - TIMG0 - SPI0/1 - SYSTIMER @@ -159,7 +159,6 @@ Light-sleep Peripheral Power Down - SARADC - SDIO - PARL_IO - - UART1 For peripherals that do not support Light-sleep context retention, if the Power management is enabled, the ``ESP_PM_NO_LIGHT_SLEEP`` lock should be held when the peripheral is working to avoid losing the working context of the peripheral when entering sleep. diff --git a/docs/zh_CN/api-reference/peripherals/uart.rst b/docs/zh_CN/api-reference/peripherals/uart.rst index 608fa135ef..902a2e71f6 100644 --- a/docs/zh_CN/api-reference/peripherals/uart.rst +++ b/docs/zh_CN/api-reference/peripherals/uart.rst @@ -66,6 +66,10 @@ UART 通信参数可以在一个步骤中完成全部配置,也可以在多个 了解配置硬件流控模式的更多信息,请参考 :example:`peripherals/uart/uart_echo`。 +.. only:: SOC_UART_SUPPORT_SLEEP_RETENTION + + 此外,置位 :cpp:member:`uart_config_t::backup_before_sleep` 会使能在进入睡眠模式前备份 UART 配置寄存器并在退出睡眠后恢复这些寄存器。这个功能使 UART 能够在系统唤醒后继续正常工作,即使其电源域在睡眠过程中被完全关闭。此选项需要用户在功耗和内存使用之间取得平衡。如果功耗不是一个问题,可以禁用这个选项来节省内存。 + 分步依次配置每个参数 """"""""""""""""""""""""""""""" diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index b970357701..63e321cacb 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -136,7 +136,7 @@ Light-sleep 外设下电 - INT_MTX - TEE/APM - IO_MUX / GPIO - - UART0 + - UART0/1 - TIMG0 - SPI0/1 - SYSTIMER @@ -159,7 +159,6 @@ Light-sleep 外设下电 - SARADC - SDIO - PARL_IO - - UART1 对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。 diff --git a/examples/bluetooth/esp_ble_mesh/aligenie_demo/README.md b/examples/bluetooth/esp_ble_mesh/aligenie_demo/README.md index cca7674483..1e9899bfce 100644 --- a/examples/bluetooth/esp_ble_mesh/aligenie_demo/README.md +++ b/examples/bluetooth/esp_ble_mesh/aligenie_demo/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-S3 | ESP32-H2 | ESP32-C6 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | +| ----------------- | ----- | ESP BLE Mesh AliGenie Example =============================