Merge branch 'feat/parlio_sleep_retention' into 'master'

feat(parlio): support sleep retention

Closes IDF-8477, IDF-9741, and IDF-9770

See merge request espressif/esp-idf!33925
This commit is contained in:
Chen Ji Chang
2024-10-22 17:26:18 +08:00
33 changed files with 471 additions and 42 deletions

View File

@@ -41,6 +41,9 @@ typedef struct {
i.e. high level of valid gpio to enable the clock output, low to disable */ 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_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 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 */ } flags; /*!< RX driver flags */
} parlio_rx_unit_config_t; } parlio_rx_unit_config_t;

View File

@@ -40,6 +40,9 @@ typedef struct {
the output clock will be controlled by the MSB bit of the data bus, 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 */ 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 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 */ } flags; /*!< Extra configuration flags */
} parlio_tx_unit_config_t; } parlio_tx_unit_config_t;

View File

@@ -18,6 +18,7 @@
#include "soc/parlio_periph.h" #include "soc/parlio_periph.h"
#include "hal/parlio_ll.h" #include "hal/parlio_ll.h"
#include "esp_private/esp_clk.h" #include "esp_private/esp_clk.h"
#include "esp_private/sleep_retention.h"
#include "parlio_private.h" #include "parlio_private.h"
static const char *TAG = "parlio"; 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_enable_bus_clock(group_id, true);
parlio_ll_reset_register(group_id); 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 // hal layer initialize
parlio_hal_init(&group->hal); parlio_hal_init(&group->hal);
group->dma_align = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); 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); _lock_release(&s_platform.mutex);
if (do_deinitialize) { 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); free(group);
ESP_LOGD(TAG, "del group(%d)", group_id); 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 */ /* the parlio unit has a reference of the group, release it now */
parlio_release_group_handle(group); 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

View File

@@ -24,6 +24,7 @@
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "esp_private/esp_gpio_reserve.h" #include "esp_private/esp_gpio_reserve.h"
#include "esp_private/gpio.h" #include "esp_private/gpio.h"
#include "esp_private/sleep_retention.h"
#if CONFIG_PARLIO_ISR_IRAM_SAFE #if CONFIG_PARLIO_ISR_IRAM_SAFE
#define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #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) #define PARLIO_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED)
#endif #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_TRIG_PERIPH_PARLIO0_BUS) // Parlio uses GDMA
#if defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AHB) #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; 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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -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; esp_err_t ret = ESP_OK;
parlio_rx_unit_handle_t unit = NULL; 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 */ /* Allocate unit memory */
unit = heap_caps_calloc(1, sizeof(parlio_rx_unit_t), PARLIO_MEM_ALLOC_CAPS); 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"); 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 #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 */ /* return RX unit handle */
*ret_unit = unit; *ret_unit = unit;

View File

@@ -270,7 +270,7 @@ static esp_err_t parlio_select_periph_clock(parlio_tx_unit_t *tx_unit, const par
#endif #endif
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true); esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
PARLIO_CLOCK_SRC_ATOMIC() { 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_enable_clock(hal->regs, true);
parlio_ll_tx_set_clock_source(hal->regs, clk_src); parlio_ll_tx_set_clock_source(hal->regs, clk_src);
// set clock division // 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"); 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 #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 // malloc unit memory
uint32_t mem_caps = PARLIO_MEM_ALLOC_CAPS; 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); 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 // GPIO Matrix/MUX configuration
ESP_GOTO_ON_ERROR(parlio_tx_unit_configure_gpio(unit, config), err, TAG, "configure gpio failed"); 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); portMUX_INITIALIZE(&unit->spinlock);
atomic_init(&unit->fsm, PARLIO_TX_FSM_INIT); atomic_init(&unit->fsm, PARLIO_TX_FSM_INIT);
// return TX unit handle // 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); while (parlio_ll_tx_is_ready(hal->regs) == false);
// turn on the core clock after we start the TX unit // turn on the core clock after we start the TX unit
parlio_ll_tx_start(hal->regs, true); 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) 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"); ESP_RETURN_ON_FALSE(tx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
parlio_tx_fsm_t expected_fsm = PARLIO_TX_FSM_INIT; 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)) { 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"); 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 // check if we need to start one pending transaction
parlio_tx_trans_desc_t *t = NULL; parlio_tx_trans_desc_t *t = NULL;
expected_fsm = PARLIO_TX_FSM_ENABLE; 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 // stop the TX engine
parlio_hal_context_t *hal = &tx_unit->base.group->hal; 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); gdma_stop(tx_unit->dma_chan);
parlio_ll_tx_start(hal->regs, false); parlio_ll_tx_start(hal->regs, false);
parlio_ll_enable_interrupt(hal->regs, PARLIO_LL_EVENT_TX_EOF, 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) { if (status & PARLIO_LL_EVENT_TX_EOF) {
parlio_ll_clear_interrupt_status(hal->regs, 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_ll_tx_start(hal->regs, false);
parlio_tx_trans_desc_t *trans_desc = NULL; parlio_tx_trans_desc_t *trans_desc = NULL;

View File

@@ -7,6 +7,10 @@ if(CONFIG_PARLIO_ISR_IRAM_SAFE)
list(REMOVE_ITEM srcs "test_parlio_rx.c") list(REMOVE_ITEM srcs "test_parlio_rx.c")
endif() 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, # In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE # the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}

View File

@@ -56,14 +56,14 @@ extern "C" {
#elif CONFIG_IDF_TARGET_ESP32P4 #elif CONFIG_IDF_TARGET_ESP32P4
#define TEST_CLK_GPIO 33 #define TEST_CLK_GPIO 33
#define TEST_VALID_GPIO 36 #define TEST_VALID_GPIO 36
#define TEST_DATA0_GPIO 20 #define TEST_DATA0_GPIO 0
#define TEST_DATA1_GPIO 21 #define TEST_DATA1_GPIO 1
#define TEST_DATA2_GPIO 22 #define TEST_DATA2_GPIO 2
#define TEST_DATA3_GPIO 23 #define TEST_DATA3_GPIO 3
#define TEST_DATA4_GPIO 45 #define TEST_DATA4_GPIO 4
#define TEST_DATA5_GPIO 46 #define TEST_DATA5_GPIO 5
#define TEST_DATA6_GPIO 47 #define TEST_DATA6_GPIO 6
#define TEST_DATA7_GPIO 48 #define TEST_DATA7_GPIO 7
#else #else
#error "Unsupported target" #error "Unsupported target"
#endif #endif

View File

@@ -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 = { parlio_rx_pulse_delimiter_config_t pls_deli_cfg = {
.valid_sig_line_id = TEST_VALID_SIG, .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, .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB,
.eof_data_len = TEST_EOF_DATA_LEN, .eof_data_len = TEST_EOF_DATA_LEN,
.timeout_ticks = 0, .timeout_ticks = 0,

View File

@@ -0,0 +1,168 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#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
}

View File

@@ -1,5 +1,6 @@
CONFIG_PM_ENABLE=y CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@@ -3,3 +3,6 @@
# #
CONFIG_ESP_TASK_WDT_INIT=n CONFIG_ESP_TASK_WDT_INIT=n
CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_HZ=1000
# primitives for checking sleep internal state
CONFIG_ESP_SLEEP_DEBUG=y

View File

@@ -915,6 +915,10 @@ config SOC_PARLIO_TX_SIZE_BY_DMA
bool bool
default y default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM config SOC_MPI_MEM_BLOCKS_NUM
int int
default 4 default 4

View File

@@ -39,6 +39,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_I2S0 = 16, SLEEP_RETENTION_MODULE_I2S0 = 16,
SLEEP_RETENTION_MODULE_ETM0 = 17, SLEEP_RETENTION_MODULE_ETM0 = 17,
SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18, SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18,
SLEEP_RETENTION_MODULE_PARLIO0 = 19,
/* modem module, which includes WiFi, BLE and 802.15.4 */ /* modem module, which includes WiFi, BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_WIFI_MAC = 26, 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_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0),
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0), 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_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_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0),
SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), 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_I2S0 \
| SLEEP_RETENTION_MODULE_BM_ETM0 \ | SLEEP_RETENTION_MODULE_BM_ETM0 \
| SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \ | SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
) )
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -370,6 +370,7 @@
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */ #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_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_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 ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4) #define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@@ -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
},
};

View File

@@ -907,6 +907,10 @@ config SOC_PARLIO_TX_RX_SHARE_INTERRUPT
bool bool
default y default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM config SOC_MPI_MEM_BLOCKS_NUM
int int
default 4 default 4

View File

@@ -41,6 +41,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18, SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18,
SLEEP_RETENTION_MODULE_TWAI0 = 19, SLEEP_RETENTION_MODULE_TWAI0 = 19,
SLEEP_RETENTION_MODULE_TWAI1 = 20, SLEEP_RETENTION_MODULE_TWAI1 = 20,
SLEEP_RETENTION_MODULE_PARLIO0 = 21,
/* Modem module, which includes WiFi, BLE and 802.15.4 */ /* Modem module, which includes WiFi, BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_WIFI_MAC = 26, 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_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR),
SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0), SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0),
SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1), 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 */ /* 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_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC),
SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), 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_TEMP_SENSOR \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \ | SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_TWAI1 \ | SLEEP_RETENTION_MODULE_BM_TWAI1 \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
) )
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -349,6 +349,7 @@
#define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */ #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_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_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 ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4) #define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@@ -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 * 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
},
};

View File

@@ -903,6 +903,10 @@ config SOC_PARLIO_TRANS_BIT_ALIGN
bool bool
default y default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM config SOC_MPI_MEM_BLOCKS_NUM
int int
default 4 default 4

View File

@@ -41,6 +41,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_ETM0 = 18, SLEEP_RETENTION_MODULE_ETM0 = 18,
SLEEP_RETENTION_MODULE_TEMP_SENSOR = 19, SLEEP_RETENTION_MODULE_TEMP_SENSOR = 19,
SLEEP_RETENTION_MODULE_TWAI0 = 20, SLEEP_RETENTION_MODULE_TWAI0 = 20,
SLEEP_RETENTION_MODULE_PARLIO0 = 21,
/* Modem module, which includes BLE and 802.15.4 */ /* Modem module, which includes BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_BLE_MAC = 28, 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_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR), 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_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 */ /* 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_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC),
SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), 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_ETM0 \
| SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \ | SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \ | SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
) )
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -346,6 +346,7 @@
#define SOC_PARLIO_RX_CLK_SUPPORT_GATING 1 /*!< Support gating RX clock */ #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_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_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */
#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */
/*--------------------------- MPI CAPS ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4) #define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@@ -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 * 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
},
};

View File

@@ -24,7 +24,7 @@
#define DR_REG_PCNT_BASE 0x60012000 #define DR_REG_PCNT_BASE 0x60012000
#define DR_REG_SOC_ETM_BASE 0x60013000 #define DR_REG_SOC_ETM_BASE 0x60013000
#define DR_REG_MCPWM_BASE 0x60014000 #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_PVT_MONITOR_BASE 0x60019000
#define DR_REG_GDMA_BASE 0x60080000 #define DR_REG_GDMA_BASE 0x60080000
#define DR_REG_SPI2_BASE 0x60081000 #define DR_REG_SPI2_BASE 0x60081000

View File

@@ -1287,6 +1287,10 @@ config SOC_PARLIO_TX_SIZE_BY_DMA
bool bool
default y default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM config SOC_MPI_MEM_BLOCKS_NUM
int int
default 4 default 4

View File

@@ -25,22 +25,21 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_TG1_WDT = 4, SLEEP_RETENTION_MODULE_TG1_WDT = 4,
SLEEP_RETENTION_MODULE_TG0_TIMER = 5, SLEEP_RETENTION_MODULE_TG0_TIMER = 5,
SLEEP_RETENTION_MODULE_TG1_TIMER = 6, 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 */ /* AHB_DMA by channel */
SLEEP_RETENTION_MODULE_AHB_DMA_CH0 = 13, SLEEP_RETENTION_MODULE_AHB_DMA_CH0 = 7,
SLEEP_RETENTION_MODULE_AHB_DMA_CH1 = 14, SLEEP_RETENTION_MODULE_AHB_DMA_CH1 = 8,
SLEEP_RETENTION_MODULE_AHB_DMA_CH2 = 15, SLEEP_RETENTION_MODULE_AHB_DMA_CH2 = 9,
/* AXI_DMA by channel */ /* AXI_DMA by channel */
SLEEP_RETENTION_MODULE_AXI_DMA_CH0 = 16, SLEEP_RETENTION_MODULE_AXI_DMA_CH0 = 10,
SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 17, SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 11,
SLEEP_RETENTION_MODULE_AXI_DMA_CH2 = 18, 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_I2S0 = 19,
SLEEP_RETENTION_MODULE_I2S1 = 20, SLEEP_RETENTION_MODULE_I2S1 = 20,
SLEEP_RETENTION_MODULE_I2S2 = 21, SLEEP_RETENTION_MODULE_I2S2 = 21,
@@ -50,6 +49,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_TWAI0 = 25, SLEEP_RETENTION_MODULE_TWAI0 = 25,
SLEEP_RETENTION_MODULE_TWAI1 = 26, SLEEP_RETENTION_MODULE_TWAI1 = 26,
SLEEP_RETENTION_MODULE_TWAI2 = 27, SLEEP_RETENTION_MODULE_TWAI2 = 27,
SLEEP_RETENTION_MODULE_PARLIO0 = 28,
SLEEP_RETENTION_MODULE_MAX = 31 SLEEP_RETENTION_MODULE_MAX = 31
} periph_retention_module_t; } 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_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0),
SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1), SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1),
SLEEP_RETENTION_MODULE_BM_TWAI2 = BIT(SLEEP_RETENTION_MODULE_TWAI2), 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 SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1
} periph_retention_module_bitmap_t; } periph_retention_module_bitmap_t;
@@ -114,11 +115,12 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_I2S1 \ | SLEEP_RETENTION_MODULE_BM_I2S1 \
| SLEEP_RETENTION_MODULE_BM_I2S2 \ | SLEEP_RETENTION_MODULE_BM_I2S2 \
| SLEEP_RETENTION_MODULE_BM_ETM0 \ | SLEEP_RETENTION_MODULE_BM_ETM0 \
| SLEEP_RETENTION_MODULE_BM_I2C0 \ | SLEEP_RETENTION_MODULE_BM_I2C0 \
| SLEEP_RETENTION_MODULE_BM_I2C1 \ | SLEEP_RETENTION_MODULE_BM_I2C1 \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \ | SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_TWAI1 \ | SLEEP_RETENTION_MODULE_BM_TWAI1 \
| SLEEP_RETENTION_MODULE_BM_TWAI2 \ | SLEEP_RETENTION_MODULE_BM_TWAI2 \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
) )
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -465,6 +465,7 @@
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */ #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_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_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 ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4) #define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@@ -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 * 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
},
};

View File

@@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -13,6 +13,10 @@
#include "soc/parl_io_reg.h" #include "soc/parl_io_reg.h"
#include "soc/parl_io_struct.h" #include "soc/parl_io_struct.h"
#endif #endif
#include "soc/regdma.h"
#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION
#include "soc/retention_periph_defs.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -39,6 +43,16 @@ typedef struct {
extern const parlio_signal_conn_t parlio_periph_signals; 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 #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -57,6 +57,7 @@ extern "C" {
#define REGDMA_ETM_LINK(_pri) ((0x1F << 8) | _pri) #define REGDMA_ETM_LINK(_pri) ((0x1F << 8) | _pri)
#define REGDMA_TSENS_LINK(_pri) ((0x20 << 8) | _pri) #define REGDMA_TSENS_LINK(_pri) ((0x20 << 8) | _pri)
#define REGDMA_TWAI_LINK(_pri) ((0x21 << 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_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
#define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0 #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_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_I2C 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_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_UART REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_TEMPERATURE_SENSOR 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 #define REGDMA_LINK_PRI_TWAI REGDMA_LINK_PRI_GENERAL_PERIPH

View File

@@ -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_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
:SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor :SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs :SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
The following peripherals are not yet supported: 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 - MCPWM
- SARADC - SARADC
- SDIO - 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. 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.

View File

@@ -158,6 +158,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs :SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
:SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor :SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs :SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
以下外设尚未支持: 以下外设尚未支持:
@@ -173,7 +174,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
- MCPWM - MCPWM
- SARADC - SARADC
- SDIO - SDIO
- PARL_IO
对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。 对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。