From e8de889cda7d73e5c835a620bd043358de3e1d7e Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Mon, 30 Sep 2024 12:17:09 +0800 Subject: [PATCH 1/3] fix(parlio_rx): fix high failure rate of test with i2s input --- .../esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index d9d84cf005..cc454aa7b4 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -368,7 +368,7 @@ TEST_CASE("parallel_rx_unit_pulse_delimiter_test_via_i2s", "[parlio_rx]") { parlio_rx_pulse_delimiter_config_t pls_deli_cfg = { .valid_sig_line_id = TEST_VALID_SIG, - .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .sample_edge = PARLIO_SAMPLE_EDGE_NEG, .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB, .eof_data_len = TEST_EOF_DATA_LEN, .timeout_ticks = 0, From e9fc43f5da56867671c9c7837357ba80ee4980c5 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Sat, 12 Oct 2024 15:20:08 +0800 Subject: [PATCH 2/3] fix(parlio): fix spelling error in reg_base.h --- components/soc/esp32h2/register/soc/reg_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/soc/esp32h2/register/soc/reg_base.h b/components/soc/esp32h2/register/soc/reg_base.h index e3801b9c9a..1a5a0e4f0a 100644 --- a/components/soc/esp32h2/register/soc/reg_base.h +++ b/components/soc/esp32h2/register/soc/reg_base.h @@ -24,7 +24,7 @@ #define DR_REG_PCNT_BASE 0x60012000 #define DR_REG_SOC_ETM_BASE 0x60013000 #define DR_REG_MCPWM_BASE 0x60014000 -#define DR_REG_PARl_IO_BASE 0x60015000 +#define DR_REG_PARL_IO_BASE 0x60015000 #define DR_REG_PVT_MONITOR_BASE 0x60019000 #define DR_REG_GDMA_BASE 0x60080000 #define DR_REG_SPI2_BASE 0x60081000 From b6645acafebad0f9d64305b48ed9d5af96342bea Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Mon, 30 Sep 2024 12:54:33 +0800 Subject: [PATCH 3/3] feat(parlio): support sleep retention --- .../include/driver/parlio_rx.h | 3 + .../include/driver/parlio_tx.h | 3 + .../esp_driver_parlio/src/parlio_common.c | 57 ++++++ .../esp_driver_parlio/src/parlio_private.h | 9 + components/esp_driver_parlio/src/parlio_rx.c | 10 ++ components/esp_driver_parlio/src/parlio_tx.c | 28 ++- .../test_apps/parlio/main/CMakeLists.txt | 4 + .../test_apps/parlio/main/test_board.h | 16 +- .../test_apps/parlio/main/test_parlio_sleep.c | 168 ++++++++++++++++++ .../test_apps/parlio/sdkconfig.ci.release | 1 + .../test_apps/parlio/sdkconfig.defaults | 3 + .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 3 + components/soc/esp32c5/include/soc/soc_caps.h | 1 + components/soc/esp32c5/parlio_periph.c | 28 +++ .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 3 + components/soc/esp32c6/include/soc/soc_caps.h | 1 + components/soc/esp32c6/parlio_periph.c | 28 ++- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 3 + components/soc/esp32h2/include/soc/soc_caps.h | 1 + components/soc/esp32h2/parlio_periph.c | 30 +++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 40 +++-- components/soc/esp32p4/include/soc/soc_caps.h | 1 + components/soc/esp32p4/parlio_periph.c | 30 +++- components/soc/include/soc/parlio_periph.h | 16 +- components/soc/include/soc/regdma.h | 2 + .../api-reference/system/power_management.rst | 2 +- .../api-reference/system/power_management.rst | 2 +- 31 files changed, 469 insertions(+), 40 deletions(-) create mode 100644 components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c diff --git a/components/esp_driver_parlio/include/driver/parlio_rx.h b/components/esp_driver_parlio/include/driver/parlio_rx.h index 3a450bd3fd..9774d871b4 100644 --- a/components/esp_driver_parlio/include/driver/parlio_rx.h +++ b/components/esp_driver_parlio/include/driver/parlio_rx.h @@ -41,6 +41,9 @@ typedef struct { i.e. high level of valid gpio to enable the clock output, low to disable */ uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */ uint32_t io_no_init: 1 __attribute__((deprecated)); /*!< Deprecated. Driver won't change the GPIO configuration in inilization. */ + uint32_t allow_pd: 1; /*!< Set to allow power down. When this flag set, the driver will backup/restore the PARLIO registers before/after entering/exist sleep mode. + By this approach, the system can power off PARLIO's power domain. + This can save power, but at the expense of more RAM being consumed. */ } flags; /*!< RX driver flags */ } parlio_rx_unit_config_t; diff --git a/components/esp_driver_parlio/include/driver/parlio_tx.h b/components/esp_driver_parlio/include/driver/parlio_tx.h index b2cb66a243..0bd9442ced 100644 --- a/components/esp_driver_parlio/include/driver/parlio_tx.h +++ b/components/esp_driver_parlio/include/driver/parlio_tx.h @@ -40,6 +40,9 @@ typedef struct { the output clock will be controlled by the MSB bit of the data bus, i.e. by data_gpio_nums[PARLIO_TX_UNIT_MAX_DATA_WIDTH-1]. High level to enable the clock output, low to disable */ uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */ + uint32_t allow_pd: 1; /*!< Set to allow power down. When this flag set, the driver will backup/restore the PARLIO registers before/after entering/exist sleep mode. + By this approach, the system can power off PARLIO's power domain. + This can save power, but at the expense of more RAM being consumed. */ } flags; /*!< Extra configuration flags */ } parlio_tx_unit_config_t; diff --git a/components/esp_driver_parlio/src/parlio_common.c b/components/esp_driver_parlio/src/parlio_common.c index 48518ddb0c..585cea006f 100644 --- a/components/esp_driver_parlio/src/parlio_common.c +++ b/components/esp_driver_parlio/src/parlio_common.c @@ -18,6 +18,7 @@ #include "soc/parlio_periph.h" #include "hal/parlio_ll.h" #include "esp_private/esp_clk.h" +#include "esp_private/sleep_retention.h" #include "parlio_private.h" static const char *TAG = "parlio"; @@ -46,6 +47,23 @@ parlio_group_t *parlio_acquire_group_handle(int group_id) parlio_ll_enable_bus_clock(group_id, true); parlio_ll_reset_register(group_id); } +#if PARLIO_USE_RETENTION_LINK + sleep_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module; + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = parlio_create_sleep_retention_link_cb, + .arg = group, + }, + }, + .depends = SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM + }; + // we only do retention init here. Allocate retention module in the unit initialization + if (sleep_retention_module_init(module_id, &init_param) != ESP_OK) { + // even though the sleep retention module init failed, PARLIO driver should still work, so just warning here + ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id); + } +#endif // PARLIO_USE_RETENTION_LINK // hal layer initialize parlio_hal_init(&group->hal); group->dma_align = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); @@ -87,6 +105,16 @@ void parlio_release_group_handle(parlio_group_t *group) _lock_release(&s_platform.mutex); if (do_deinitialize) { +#if PARLIO_USE_RETENTION_LINK + const periph_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module; + if (sleep_retention_get_created_modules() & BIT(module_id)) { + assert(sleep_retention_get_inited_modules() & BIT(module_id)); + sleep_retention_module_free(module_id); + } + if (sleep_retention_get_inited_modules() & BIT(module_id)) { + sleep_retention_module_deinit(module_id); + } +#endif // PARLIO_USE_RETENTION_LINK free(group); ESP_LOGD(TAG, "del group(%d)", group_id); } @@ -147,3 +175,32 @@ void parlio_unregister_unit_from_group(parlio_unit_base_handle_t unit) /* the parlio unit has a reference of the group, release it now */ parlio_release_group_handle(group); } + +#if PARLIO_USE_RETENTION_LINK +esp_err_t parlio_create_sleep_retention_link_cb(void *arg) +{ + parlio_group_t *group = (parlio_group_t *)arg; + int group_id = group->group_id; + sleep_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module; + esp_err_t err = sleep_retention_entries_create(parlio_reg_retention_info[group_id].regdma_entry_array, + parlio_reg_retention_info[group_id].array_size, + REGDMA_LINK_PRI_PARLIO, module_id); + ESP_RETURN_ON_ERROR(err, TAG, "create retention link failed"); + return ESP_OK; +} + +void parlio_create_retention_module(parlio_group_t *group) +{ + int group_id = group->group_id; + sleep_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module; + + _lock_acquire(&s_platform.mutex); + if ((sleep_retention_get_inited_modules() & BIT(module_id)) && !(sleep_retention_get_created_modules() & BIT(module_id))) { + if (sleep_retention_module_allocate(module_id) != ESP_OK) { + // even though the sleep retention module create failed, PARLIO driver should still work, so just warning here + ESP_LOGW(TAG, "create retention module failed, power domain can't turn off"); + } + } + _lock_release(&s_platform.mutex); +} +#endif // PARLIO_USE_RETENTION_LINK diff --git a/components/esp_driver_parlio/src/parlio_private.h b/components/esp_driver_parlio/src/parlio_private.h index d728359b09..b76ec8ba83 100644 --- a/components/esp_driver_parlio/src/parlio_private.h +++ b/components/esp_driver_parlio/src/parlio_private.h @@ -24,6 +24,7 @@ #include "esp_private/periph_ctrl.h" #include "esp_private/esp_gpio_reserve.h" #include "esp_private/gpio.h" +#include "esp_private/sleep_retention.h" #if CONFIG_PARLIO_ISR_IRAM_SAFE #define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) @@ -44,6 +45,9 @@ #define PARLIO_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED) #endif +// Use retention link only when the target supports sleep retention is enabled +#define PARLIO_USE_RETENTION_LINK (SOC_PARLIO_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) + #if defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS) // Parlio uses GDMA #if defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AHB) typedef dma_descriptor_align4_t parlio_dma_desc_t; @@ -149,6 +153,11 @@ esp_err_t parlio_register_unit_to_group(parlio_unit_base_handle_t unit); */ void parlio_unregister_unit_from_group(parlio_unit_base_handle_t unit); +#if PARLIO_USE_RETENTION_LINK +esp_err_t parlio_create_sleep_retention_link_cb(void *arg); +void parlio_create_retention_module(parlio_group_t *group); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index 12a9150b1a..97acef1973 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -620,6 +620,10 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un esp_err_t ret = ESP_OK; parlio_rx_unit_handle_t unit = NULL; +#if !SOC_PARLIO_SUPPORT_SLEEP_RETENTION + ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported"); +#endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION + /* Allocate unit memory */ unit = heap_caps_calloc(1, sizeof(parlio_rx_unit_t), PARLIO_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no memory for rx unit"); @@ -676,6 +680,12 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un } #endif // SOC_PARLIO_RX_CLK_SUPPORT_GATING +#if PARLIO_USE_RETENTION_LINK + if (config->flags.allow_pd != 0) { + parlio_create_retention_module(group); + } +#endif // PARLIO_USE_RETENTION_LINK + /* return RX unit handle */ *ret_unit = unit; diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index e8ebaf8652..b7493b73cb 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -270,7 +270,7 @@ static esp_err_t parlio_select_periph_clock(parlio_tx_unit_t *tx_unit, const par #endif esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true); PARLIO_CLOCK_SRC_ATOMIC() { - // turn on the tx module clock to sync the register configuration to the module + // turn on the tx module clock to sync the clock divider configuration because of the CDC (Cross Domain Crossing) parlio_ll_tx_enable_clock(hal->regs, true); parlio_ll_tx_set_clock_source(hal->regs, clk_src); // set clock division @@ -309,6 +309,10 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un ESP_RETURN_ON_FALSE(config->flags.clk_gate_en == 0, ESP_ERR_NOT_SUPPORTED, TAG, "clock gating is not supported"); #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING +#if !SOC_PARLIO_SUPPORT_SLEEP_RETENTION + ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported"); +#endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION + // malloc unit memory uint32_t mem_caps = PARLIO_MEM_ALLOC_CAPS; unit = heap_caps_calloc(1, sizeof(parlio_tx_unit_t) + sizeof(parlio_tx_trans_desc_t) * config->trans_queue_depth, mem_caps); @@ -381,6 +385,12 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un // GPIO Matrix/MUX configuration ESP_GOTO_ON_ERROR(parlio_tx_unit_configure_gpio(unit, config), err, TAG, "configure gpio failed"); +#if PARLIO_USE_RETENTION_LINK + if (config->flags.allow_pd != 0) { + parlio_create_retention_module(group); + } +#endif // PARLIO_USE_RETENTION_LINK + portMUX_INITIALIZE(&unit->spinlock); atomic_init(&unit->fsm, PARLIO_TX_FSM_INIT); // return TX unit handle @@ -468,13 +478,11 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio while (parlio_ll_tx_is_ready(hal->regs) == false); // turn on the core clock after we start the TX unit parlio_ll_tx_start(hal->regs, true); - PARLIO_CLOCK_SRC_ATOMIC() { - parlio_ll_tx_enable_clock(hal->regs, true); - } } esp_err_t parlio_tx_unit_enable(parlio_tx_unit_handle_t tx_unit) { + parlio_hal_context_t *hal = &tx_unit->base.group->hal; ESP_RETURN_ON_FALSE(tx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); parlio_tx_fsm_t expected_fsm = PARLIO_TX_FSM_INIT; if (atomic_compare_exchange_strong(&tx_unit->fsm, &expected_fsm, PARLIO_TX_FSM_ENABLE_WAIT)) { @@ -489,6 +497,11 @@ esp_err_t parlio_tx_unit_enable(parlio_tx_unit_handle_t tx_unit) ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "unit not in init state"); } + // enable clock output + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_enable_clock(hal->regs, true); + } + // check if we need to start one pending transaction parlio_tx_trans_desc_t *t = NULL; expected_fsm = PARLIO_TX_FSM_ENABLE; @@ -531,6 +544,10 @@ esp_err_t parlio_tx_unit_disable(parlio_tx_unit_handle_t tx_unit) // stop the TX engine parlio_hal_context_t *hal = &tx_unit->base.group->hal; + // disable clock output + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_tx_enable_clock(hal->regs, false); + } gdma_stop(tx_unit->dma_chan); parlio_ll_tx_start(hal->regs, false); parlio_ll_enable_interrupt(hal->regs, PARLIO_LL_EVENT_TX_EOF, false); @@ -621,9 +638,6 @@ static void IRAM_ATTR parlio_tx_default_isr(void *args) if (status & PARLIO_LL_EVENT_TX_EOF) { parlio_ll_clear_interrupt_status(hal->regs, PARLIO_LL_EVENT_TX_EOF); - PARLIO_CLOCK_SRC_ATOMIC() { - parlio_ll_tx_enable_clock(hal->regs, false); - } parlio_ll_tx_start(hal->regs, false); parlio_tx_trans_desc_t *trans_desc = NULL; diff --git a/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt b/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt index 3ee6db54ce..6d465c10d4 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt +++ b/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt @@ -7,6 +7,10 @@ if(CONFIG_PARLIO_ISR_IRAM_SAFE) list(REMOVE_ITEM srcs "test_parlio_rx.c") endif() +if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED AND CONFIG_PM_ENABLE) + list(APPEND srcs "test_parlio_sleep.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 ${srcs} diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h index da22296e39..36c4931acb 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h @@ -56,14 +56,14 @@ extern "C" { #elif CONFIG_IDF_TARGET_ESP32P4 #define TEST_CLK_GPIO 33 #define TEST_VALID_GPIO 36 -#define TEST_DATA0_GPIO 20 -#define TEST_DATA1_GPIO 21 -#define TEST_DATA2_GPIO 22 -#define TEST_DATA3_GPIO 23 -#define TEST_DATA4_GPIO 45 -#define TEST_DATA5_GPIO 46 -#define TEST_DATA6_GPIO 47 -#define TEST_DATA7_GPIO 48 +#define TEST_DATA0_GPIO 0 +#define TEST_DATA1_GPIO 1 +#define TEST_DATA2_GPIO 2 +#define TEST_DATA3_GPIO 3 +#define TEST_DATA4_GPIO 4 +#define TEST_DATA5_GPIO 5 +#define TEST_DATA6_GPIO 6 +#define TEST_DATA7_GPIO 7 #else #error "Unsupported target" #endif diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c new file mode 100644 index 0000000000..047a19ca4c --- /dev/null +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c @@ -0,0 +1,168 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "driver/parlio_tx.h" +#include "driver/parlio_rx.h" +#include "driver/gpio.h" +#include "soc/soc_caps.h" +#include "soc/parl_io_struct.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/esp_pmu.h" +#include "esp_attr.h" +#include "test_board.h" + +TEST_PARLIO_CALLBACK_ATTR +static bool test_parlio_rx_done_callback(parlio_rx_unit_handle_t rx_unit, const parlio_rx_event_data_t *edata, void *user_ctx) +{ + BaseType_t high_task_wakeup = pdFALSE; + TaskHandle_t task = (TaskHandle_t)user_ctx; + vTaskNotifyGiveFromISR(task, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +#define TEST_PAYLOAD_SIZE 64 +static void test_parlio_sleep_retention(bool allow_pd) +{ + printf("install parlio tx unit\r\n"); + parlio_tx_unit_handle_t tx_unit = NULL; + parlio_tx_unit_config_t tx_config = { + .clk_src = PARLIO_CLK_SRC_DEFAULT, + .data_width = 4, + .clk_in_gpio_num = -1, // use internal clock source + .valid_gpio_num = TEST_VALID_GPIO, + .clk_out_gpio_num = TEST_CLK_GPIO, + .data_gpio_nums = { + TEST_DATA0_GPIO, + TEST_DATA1_GPIO, + TEST_DATA2_GPIO, + TEST_DATA3_GPIO, + }, + .output_clk_freq_hz = 1 * 1000 * 1000, + .trans_queue_depth = 8, + .max_transfer_size = 128, + .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB, + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .flags.allow_pd = allow_pd, + }; + TEST_ESP_OK(parlio_new_tx_unit(&tx_config, &tx_unit)); + + printf("send packets and check event is fired\r\n"); + parlio_transmit_config_t transmit_config = { + .idle_value = 0x00, + }; + uint8_t tx_payload[TEST_PAYLOAD_SIZE] = {0}; + for (int i = 0; i < TEST_PAYLOAD_SIZE; i++) { + tx_payload[i] = i; + } + + printf("install parlio rx unit\r\n"); + parlio_rx_unit_handle_t rx_unit = NULL; + parlio_rx_delimiter_handle_t deli = NULL; + + parlio_rx_unit_config_t rx_config = { + .trans_queue_depth = 10, + .max_recv_size = 1024, + .data_width = 4, + .clk_src = PARLIO_CLK_SRC_DEFAULT, + .ext_clk_freq_hz = 0, + .clk_in_gpio_num = -1, + .exp_clk_freq_hz = 1 * 1000 * 1000, + .clk_out_gpio_num = -1, + .valid_gpio_num = TEST_VALID_GPIO, + .data_gpio_nums = { + TEST_DATA0_GPIO, + TEST_DATA1_GPIO, + TEST_DATA2_GPIO, + TEST_DATA3_GPIO, + }, + .flags = { + .clk_gate_en = false, + .allow_pd = allow_pd, + } + }; + rx_config.flags.free_clk = 1; + TEST_ESP_OK(parlio_new_rx_unit(&rx_config, &rx_unit)); + + parlio_rx_level_delimiter_config_t lvl_deli_cfg = { + .valid_sig_line_id = PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1, + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB, + .eof_data_len = TEST_PAYLOAD_SIZE, + .timeout_ticks = 0, + .flags = { + .active_low_en = 0, + }, + }; + TEST_ESP_OK(parlio_new_rx_level_delimiter(&lvl_deli_cfg, &deli)); + + printf("register receive_done event callback\r\n"); + parlio_rx_event_callbacks_t rx_cbs = { + .on_receive_done = test_parlio_rx_done_callback, + }; + TEST_ESP_OK(parlio_rx_unit_register_event_callbacks(rx_unit, &rx_cbs, xTaskGetCurrentTaskHandle())); + + parlio_receive_config_t recv_config = { + .delimiter = deli, + .flags.partial_rx_en = false, + }; + __attribute__((aligned(TEST_PAYLOAD_SIZE))) uint8_t rx_payload[TEST_PAYLOAD_SIZE] = {0}; + + // go to sleep + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + printf("go to light sleep for 2 seconds\r\n"); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(true)); +#endif + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000)); + TEST_ESP_OK(esp_light_sleep_start()); + + printf("Waked up! Let's see if PARLIO driver can still work...\r\n"); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif + + printf("check if the sleep happened as expected\r\n"); + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); +#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION + // check if the power domain also is powered down + TEST_ASSERT_EQUAL(allow_pd ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); +#endif + esp_sleep_set_sleep_context(NULL); + + printf("Testing tx and rx after sleep...\n"); + TEST_ESP_OK(parlio_tx_unit_enable(tx_unit)); + TEST_ESP_OK(parlio_rx_unit_enable(rx_unit, 1)); + TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, rx_payload, TEST_PAYLOAD_SIZE, &recv_config)); + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, tx_payload, TEST_PAYLOAD_SIZE * sizeof(uint8_t) * 8, &transmit_config)); + TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(1000))); + for (int i = 0; i < TEST_PAYLOAD_SIZE; i++) { + printf("%.2d ", (rx_payload[i])); + TEST_ASSERT_EQUAL(tx_payload[i], rx_payload[i]); + if ((i + 1) % 16 == 0) { + printf("\n"); + } + } + TEST_ESP_OK(parlio_tx_unit_disable(tx_unit)); + TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); + TEST_ESP_OK(parlio_rx_unit_disable(rx_unit)); + TEST_ESP_OK(parlio_del_rx_delimiter(deli)); + TEST_ESP_OK(parlio_del_rx_unit(rx_unit)); +} + +TEST_CASE("parlio light sleep", "[parlio]") +{ + test_parlio_sleep_retention(false); +#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION + test_parlio_sleep_retention(true); +#endif +} diff --git a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release index 91d93f163e..17aaee1e8e 100644 --- a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.ci.release +++ b/components/esp_driver_parlio/test_apps/parlio/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/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults index 448bb50f82..e8b3e421f0 100644 --- a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults +++ b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults @@ -3,3 +3,6 @@ # CONFIG_ESP_TASK_WDT_INIT=n CONFIG_FREERTOS_HZ=1000 + +# primitives for checking sleep internal state +CONFIG_ESP_SLEEP_DEBUG=y diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index d8776c93c8..40040f93f1 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -915,6 +915,10 @@ config SOC_PARLIO_TX_SIZE_BY_DMA bool default y +config SOC_PARLIO_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32c5/include/soc/retention_periph_defs.h b/components/soc/esp32c5/include/soc/retention_periph_defs.h index 8f3db9db68..457bf2470a 100644 --- a/components/soc/esp32c5/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c5/include/soc/retention_periph_defs.h @@ -39,6 +39,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_I2S0 = 16, SLEEP_RETENTION_MODULE_ETM0 = 17, SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18, + SLEEP_RETENTION_MODULE_PARLIO0 = 19, /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -80,6 +81,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0), SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR), + SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0), SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), @@ -103,6 +105,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_I2S0 \ | SLEEP_RETENTION_MODULE_BM_ETM0 \ | SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \ + | SLEEP_RETENTION_MODULE_BM_PARLIO0 \ ) #ifdef __cplusplus } diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index ba33e35b99..18e6338525 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -370,6 +370,7 @@ #define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */ #define SOC_PARLIO_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */ #define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */ +#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ /*--------------------------- MPI CAPS ---------------------------------------*/ #define SOC_MPI_MEM_BLOCKS_NUM (4) diff --git a/components/soc/esp32c5/parlio_periph.c b/components/soc/esp32c5/parlio_periph.c index 142e461cf1..bd17bfceb1 100644 --- a/components/soc/esp32c5/parlio_periph.c +++ b/components/soc/esp32c5/parlio_periph.c @@ -48,3 +48,31 @@ const parlio_signal_conn_t parlio_periph_signals = { }, }, }; + +/** + * PARLIO Registers to be saved during sleep retention + * - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG + * - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG + * - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG + * - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG +*/ +#define PARLIO_RETENTION_REGS_CNT 8 +#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0) +static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t parlio_regs_retention[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), \ + PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, \ + PARLIO_RETENTION_REGS_CNT, 0, 0, \ + parlio_regs_map[0], parlio_regs_map[1], \ + parlio_regs_map[2], parlio_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +}; +const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = { + [0] = { + .regdma_entry_array = parlio_regs_retention, + .array_size = ARRAY_SIZE(parlio_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_PARLIO0 + }, +}; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index f0617c05ea..77399c0234 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -907,6 +907,10 @@ config SOC_PARLIO_TX_RX_SHARE_INTERRUPT bool default y +config SOC_PARLIO_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32c6/include/soc/retention_periph_defs.h b/components/soc/esp32c6/include/soc/retention_periph_defs.h index 12fefa081a..3ae0c4da09 100644 --- a/components/soc/esp32c6/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c6/include/soc/retention_periph_defs.h @@ -41,6 +41,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18, SLEEP_RETENTION_MODULE_TWAI0 = 19, SLEEP_RETENTION_MODULE_TWAI1 = 20, + SLEEP_RETENTION_MODULE_PARLIO0 = 21, /* Modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -78,6 +79,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR), SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0), SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1), + SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0), /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), @@ -105,6 +107,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \ | SLEEP_RETENTION_MODULE_BM_TWAI0 \ | SLEEP_RETENTION_MODULE_BM_TWAI1 \ + | SLEEP_RETENTION_MODULE_BM_PARLIO0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index fcdd897de5..ca133facdf 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -349,6 +349,7 @@ #define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */ #define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */ #define SOC_PARLIO_TX_RX_SHARE_INTERRUPT 1 /*!< TX and RX unit share the same interrupt source number */ +#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ /*--------------------------- MPI CAPS ---------------------------------------*/ #define SOC_MPI_MEM_BLOCKS_NUM (4) diff --git a/components/soc/esp32c6/parlio_periph.c b/components/soc/esp32c6/parlio_periph.c index 40ac06320c..f060ee1a9e 100644 --- a/components/soc/esp32c6/parlio_periph.c +++ b/components/soc/esp32c6/parlio_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,3 +64,29 @@ const parlio_signal_conn_t parlio_periph_signals = { }, }, }; + +/** + * PARLIO Registers to be saved during sleep retention + * - Configuration registers, e.g.: PARL_IO_RX_CFG0_REG, PARL_IO_RX_CFG1_REG, PARL_IO_TX_CFG0_REG, PARL_IO_TX_CFG1_REG, PARL_IO_CLK_REG + * - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG +*/ +#define PARLIO_RETENTION_REGS_CNT 6 +#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0) +static const uint32_t parlio_regs_map[4] = {0x2f, 0x0, 0x100, 0x0}; +static const regdma_entries_config_t parlio_regs_retention[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), \ + PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, \ + PARLIO_RETENTION_REGS_CNT, 0, 0, \ + parlio_regs_map[0], parlio_regs_map[1], \ + parlio_regs_map[2], parlio_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +}; +const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = { + [0] = { + .regdma_entry_array = parlio_regs_retention, + .array_size = ARRAY_SIZE(parlio_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_PARLIO0 + }, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 898a807419..709f00fcd2 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -903,6 +903,10 @@ config SOC_PARLIO_TRANS_BIT_ALIGN bool default y +config SOC_PARLIO_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32h2/include/soc/retention_periph_defs.h b/components/soc/esp32h2/include/soc/retention_periph_defs.h index c172edab27..2ab2503351 100644 --- a/components/soc/esp32h2/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h2/include/soc/retention_periph_defs.h @@ -41,6 +41,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_ETM0 = 18, SLEEP_RETENTION_MODULE_TEMP_SENSOR = 19, SLEEP_RETENTION_MODULE_TWAI0 = 20, + SLEEP_RETENTION_MODULE_PARLIO0 = 21, /* Modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BLE_MAC = 28, @@ -76,6 +77,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR), SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0), + SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0), /* modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), @@ -101,6 +103,7 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_ETM0 \ | SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \ | SLEEP_RETENTION_MODULE_BM_TWAI0 \ + | SLEEP_RETENTION_MODULE_BM_PARLIO0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 77e49d37f7..477e5cc156 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -346,6 +346,7 @@ #define SOC_PARLIO_RX_CLK_SUPPORT_GATING 1 /*!< Support gating RX clock */ #define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */ #define SOC_PARLIO_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */ +#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ /*--------------------------- MPI CAPS ---------------------------------------*/ #define SOC_MPI_MEM_BLOCKS_NUM (4) diff --git a/components/soc/esp32h2/parlio_periph.c b/components/soc/esp32h2/parlio_periph.c index 6cc86f13cb..bd17bfceb1 100644 --- a/components/soc/esp32h2/parlio_periph.c +++ b/components/soc/esp32h2/parlio_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,3 +48,31 @@ const parlio_signal_conn_t parlio_periph_signals = { }, }, }; + +/** + * PARLIO Registers to be saved during sleep retention + * - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG + * - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG + * - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG + * - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG +*/ +#define PARLIO_RETENTION_REGS_CNT 8 +#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0) +static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t parlio_regs_retention[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), \ + PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, \ + PARLIO_RETENTION_REGS_CNT, 0, 0, \ + parlio_regs_map[0], parlio_regs_map[1], \ + parlio_regs_map[2], parlio_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +}; +const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = { + [0] = { + .regdma_entry_array = parlio_regs_retention, + .array_size = ARRAY_SIZE(parlio_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_PARLIO0 + }, +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 4429cd6ae9..bbdb31b03a 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1287,6 +1287,10 @@ config SOC_PARLIO_TX_SIZE_BY_DMA bool default y +config SOC_PARLIO_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MPI_MEM_BLOCKS_NUM int default 4 diff --git a/components/soc/esp32p4/include/soc/retention_periph_defs.h b/components/soc/esp32p4/include/soc/retention_periph_defs.h index 8e0b575377..241699c8f0 100644 --- a/components/soc/esp32p4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32p4/include/soc/retention_periph_defs.h @@ -25,22 +25,21 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_TG1_WDT = 4, SLEEP_RETENTION_MODULE_TG0_TIMER = 5, SLEEP_RETENTION_MODULE_TG1_TIMER = 6, - /* MISC Peripherals */ - SLEEP_RETENTION_MODULE_UART0 = 7, - SLEEP_RETENTION_MODULE_UART1 = 8, - SLEEP_RETENTION_MODULE_UART2 = 9, - SLEEP_RETENTION_MODULE_UART3 = 10, - SLEEP_RETENTION_MODULE_UART4 = 11, - SLEEP_RETENTION_MODULE_RMT0 = 12, /* AHB_DMA by channel */ - SLEEP_RETENTION_MODULE_AHB_DMA_CH0 = 13, - SLEEP_RETENTION_MODULE_AHB_DMA_CH1 = 14, - SLEEP_RETENTION_MODULE_AHB_DMA_CH2 = 15, + SLEEP_RETENTION_MODULE_AHB_DMA_CH0 = 7, + SLEEP_RETENTION_MODULE_AHB_DMA_CH1 = 8, + SLEEP_RETENTION_MODULE_AHB_DMA_CH2 = 9, /* AXI_DMA by channel */ - SLEEP_RETENTION_MODULE_AXI_DMA_CH0 = 16, - SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 17, - SLEEP_RETENTION_MODULE_AXI_DMA_CH2 = 18, - + SLEEP_RETENTION_MODULE_AXI_DMA_CH0 = 10, + SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 11, + SLEEP_RETENTION_MODULE_AXI_DMA_CH2 = 12, + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_UART0 = 13, + SLEEP_RETENTION_MODULE_UART1 = 14, + SLEEP_RETENTION_MODULE_UART2 = 15, + SLEEP_RETENTION_MODULE_UART3 = 16, + SLEEP_RETENTION_MODULE_UART4 = 17, + SLEEP_RETENTION_MODULE_RMT0 = 18, SLEEP_RETENTION_MODULE_I2S0 = 19, SLEEP_RETENTION_MODULE_I2S1 = 20, SLEEP_RETENTION_MODULE_I2S2 = 21, @@ -50,6 +49,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_TWAI0 = 25, SLEEP_RETENTION_MODULE_TWAI1 = 26, SLEEP_RETENTION_MODULE_TWAI2 = 27, + SLEEP_RETENTION_MODULE_PARLIO0 = 28, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -89,6 +89,7 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0), SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1), SLEEP_RETENTION_MODULE_BM_TWAI2 = BIT(SLEEP_RETENTION_MODULE_TWAI2), + SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; @@ -114,11 +115,12 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_I2S1 \ | SLEEP_RETENTION_MODULE_BM_I2S2 \ | SLEEP_RETENTION_MODULE_BM_ETM0 \ - | SLEEP_RETENTION_MODULE_BM_I2C0 \ - | SLEEP_RETENTION_MODULE_BM_I2C1 \ - | SLEEP_RETENTION_MODULE_BM_TWAI0 \ - | SLEEP_RETENTION_MODULE_BM_TWAI1 \ - | SLEEP_RETENTION_MODULE_BM_TWAI2 \ + | SLEEP_RETENTION_MODULE_BM_I2C0 \ + | SLEEP_RETENTION_MODULE_BM_I2C1 \ + | SLEEP_RETENTION_MODULE_BM_TWAI0 \ + | SLEEP_RETENTION_MODULE_BM_TWAI1 \ + | SLEEP_RETENTION_MODULE_BM_TWAI2 \ + | SLEEP_RETENTION_MODULE_BM_PARLIO0 \ ) #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index f132944271..06ad4b545e 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -465,6 +465,7 @@ #define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */ #define SOC_PARLIO_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */ #define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */ +#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ /*--------------------------- MPI CAPS ---------------------------------------*/ #define SOC_MPI_MEM_BLOCKS_NUM (4) diff --git a/components/soc/esp32p4/parlio_periph.c b/components/soc/esp32p4/parlio_periph.c index 5dcafc7206..62ab0ed295 100644 --- a/components/soc/esp32p4/parlio_periph.c +++ b/components/soc/esp32p4/parlio_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,3 +64,31 @@ const parlio_signal_conn_t parlio_periph_signals = { }, }, }; + +/** + * PARLIO Registers to be saved during sleep retention + * - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG + * - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG + * - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG + * - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG +*/ +#define PARLIO_RETENTION_REGS_CNT 8 +#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0) +static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t parlio_regs_retention[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), + PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, + PARLIO_RETENTION_REGS_CNT, 0, 0, + parlio_regs_map[0], parlio_regs_map[1], + parlio_regs_map[2], parlio_regs_map[3]), + .owner = ENTRY(0)}, +}; +const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = { + [0] = { + .regdma_entry_array = parlio_regs_retention, + .array_size = ARRAY_SIZE(parlio_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_PARLIO0 + }, +}; diff --git a/components/soc/include/soc/parlio_periph.h b/components/soc/include/soc/parlio_periph.h index c9781a048f..3bb4de72b0 100644 --- a/components/soc/include/soc/parlio_periph.h +++ b/components/soc/include/soc/parlio_periph.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,10 @@ #include "soc/parl_io_reg.h" #include "soc/parl_io_struct.h" #endif +#include "soc/regdma.h" +#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION +#include "soc/retention_periph_defs.h" +#endif #ifdef __cplusplus extern "C" { @@ -39,6 +43,16 @@ typedef struct { extern const parlio_signal_conn_t parlio_periph_signals; +#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION +typedef struct { + const periph_retention_module_t retention_module; + const regdma_entries_config_t *regdma_entry_array; + uint32_t array_size; +} parlio_reg_retention_info_t; + +extern const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS]; +#endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION + #endif #ifdef __cplusplus diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index 350adfcf88..527b9b99e5 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -57,6 +57,7 @@ extern "C" { #define REGDMA_ETM_LINK(_pri) ((0x1F << 8) | _pri) #define REGDMA_TSENS_LINK(_pri) ((0x20 << 8) | _pri) #define REGDMA_TWAI_LINK(_pri) ((0x21 << 8) | _pri) +#define REGDMA_PARLIO_LINK(_pri) ((0x22 << 8) | _pri) #define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri) #define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0 @@ -75,6 +76,7 @@ extern "C" { #define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_I2S REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_PARLIO REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_UART REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_TEMPERATURE_SENSOR REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_TWAI REGDMA_LINK_PRI_GENERAL_PERIPH diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index 842a705d58..76c20eb2d5 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -158,6 +158,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs :SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor :SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs + :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO The following peripherals are not yet supported: @@ -173,7 +174,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to - MCPWM - SARADC - SDIO - - PARL_IO 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/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index 6dae9f27e5..5a22f43699 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -158,6 +158,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs :SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor :SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs + :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO 以下外设尚未支持: @@ -173,7 +174,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, - MCPWM - SARADC - SDIO - - PARL_IO 对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。