Merge branch 'feature/dma2d_ppa_sleep_retention_support_v5.4' into 'release/v5.4'

feat(ppa): add sleep retention support for DMA2D and PPA (v5.4)

See merge request espressif/esp-idf!50356
This commit is contained in:
morris
2026-07-07 10:34:39 +08:00
20 changed files with 609 additions and 157 deletions
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -39,6 +39,11 @@ typedef struct {
ppa_data_burst_length_t data_burst_length; /*!< The desired data burst length for all the transactions of the client.
Use a small burst length will decrease PPA performance, but can save burst bandwidth for other peripheral usages.
By default, it will be at the maximum burst length, `PPA_DATA_BURST_LENGTH_128` */
struct {
uint32_t allow_pd: 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode.
This can save power, but at the expense of more RAM being consumed to save register context.
All clients must have the same value for this flag. */
} flags; /*!< Configuration flags */
} ppa_client_config_t;
/**
+66
View File
@@ -30,7 +30,12 @@
#include "hal/ppa_hal.h"
#include "hal/ppa_ll.h"
#include "hal/ppa_types.h"
#include "soc/ppa_periph.h"
#include "hal/color_hal.h"
#include "hal/color_types.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/sleep_retention.h"
#include "soc/soc_caps.h"
static const char *TAG = "ppa_core";
@@ -50,6 +55,25 @@ const dma2d_trans_on_picked_callback_t ppa_oper_trans_on_picked_func[PPA_OPERATI
[PPA_OPERATION_FILL] = ppa_fill_transaction_on_picked,
};
/** PPA Power Management Strategy
*
* SRM and Blending have separate CPU_FREQ_MAX PM locks, and each PM lock is acquired whenever there is PPA operation in process.
*
* When no PPA operation is in process, sleep can happen, and PPA domain can be powered down if allow_pd is set.
* Necessary register context will be saved and restored by sleep retention.
*/
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
static esp_err_t ppa_create_sleep_retention_link_cb(void *arg)
{
sleep_retention_module_t module = ppa_reg_retention_info.module;
esp_err_t err = sleep_retention_entries_create(ppa_reg_retention_info.regdma_entry_array,
ppa_reg_retention_info.array_size,
REGDMA_LINK_PRI_PPA, module);
return err;
}
#endif
static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine)
{
esp_err_t ret = ESP_OK;
@@ -182,6 +206,35 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
ESP_LOGE(TAG, "install 2D-DMA failed");
goto wrap_up;
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
s_platform.flags.allow_pd = config->flags.allow_pd; // Uses the first acquired engine's allow_pd flag as the platform's allow_pd flag
// Initialize sleep retention module for PPA
sleep_retention_module_t module = ppa_reg_retention_info.module;
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = {
.handle = ppa_create_sleep_retention_link_cb,
.arg = NULL,
},
},
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
};
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
// even though the sleep retention module init failed, PPA driver should still work, so just warning here
ESP_LOGW(TAG, "init sleep retention failed, power domain may be turned off during sleep");
} else if (s_platform.flags.allow_pd) {
if (sleep_retention_module_allocate(module) != ESP_OK) {
ESP_LOGW(TAG, "fail to allocate retention link list");
// don't call sleep_retention_module_deinit here, otherwise PPA peripheral may be powered off during sleep
}
}
} else {
if (s_platform.flags.allow_pd != config->flags.allow_pd) {
ESP_LOGW(TAG, "allow_pd flag mismatch among clients, will follow flags.allow_pd = %d", s_platform.flags.allow_pd);
}
#endif
}
}
wrap_up:
@@ -242,6 +295,17 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine)
if (!s_platform.srm && !s_platform.blending) {
assert(s_platform.srm_engine_ref_count == 0 && s_platform.blend_engine_ref_count == 0);
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
sleep_retention_module_t module = ppa_reg_retention_info.module;
if (sleep_retention_is_module_created(module)) {
sleep_retention_module_free(module);
}
if (sleep_retention_is_module_inited(module)) {
sleep_retention_module_deinit(module);
}
s_platform.flags.allow_pd = false;
#endif
if (s_platform.dma2d_pool_handle) {
dma2d_release_pool(s_platform.dma2d_pool_handle); // TODO: check return value. If not ESP_OK, then must be error on other 2D-DMA clients :( Give a warning log?
s_platform.dma2d_pool_handle = NULL;
@@ -279,11 +343,13 @@ esp_err_t ppa_register_client(const ppa_client_config_t *config, ppa_client_hand
if (config->oper_type == PPA_OPERATION_SRM) {
ppa_engine_config_t engine_config = {
.engine = PPA_ENGINE_TYPE_SRM,
.flags.allow_pd = config->flags.allow_pd,
};
ESP_GOTO_ON_ERROR(ppa_engine_acquire(&engine_config, &client->engine), err, TAG, "unable to acquire SRM engine");
} else if (config->oper_type == PPA_OPERATION_BLEND || config->oper_type == PPA_OPERATION_FILL) {
ppa_engine_config_t engine_config = {
.engine = PPA_ENGINE_TYPE_BLEND,
.flags.allow_pd = config->flags.allow_pd,
};
ESP_GOTO_ON_ERROR(ppa_engine_acquire(&engine_config, &client->engine), err, TAG, "unable to acquire Blending engine");
}
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -74,6 +74,9 @@ typedef struct ppa_blend_engine_t {
typedef struct {
ppa_engine_type_t engine; // Engine type
struct {
uint32_t allow_pd: 1; // If set, engine allows the power domain to be powered off when system enters sleep mode
} flags; // Configuration flags
} ppa_engine_config_t;
/******************************** CLIENT *************************************/
@@ -237,6 +240,9 @@ struct ppa_platform_t {
uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release
size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size
uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size
struct {
uint32_t allow_pd: 1; // If set, driver allows the power domain to be powered off when system enters sleep mode
} flags; // Configuration flags
};
#ifdef __cplusplus
@@ -5,5 +5,5 @@ set(srcs "test_app_main.c"
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "."
PRIV_REQUIRES esp_driver_ppa esp_psram unity esp_mm
PRIV_REQUIRES esp_driver_ppa esp_psram unity esp_mm esp_pm
WHOLE_ARCHIVE)
@@ -19,6 +19,12 @@
#include "esp_cache.h"
#include "ppa_performance.h"
#include "esp_random.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_pm.h"
#include "esp_clk_tree.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/esp_pmu.h"
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
@@ -264,7 +270,20 @@ TEST_CASE("ppa_pending_transactions_in_queue", "[PPA]")
free(buf_2);
}
TEST_CASE("ppa_srm_basic_data_correctness_check", "[PPA]")
static __attribute__((unused)) void enable_pm_strategy(bool auto_light_sleep)
{
uint32_t xtal_hz = 0;
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz);
esp_pm_config_t pm_config = {};
pm_config.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
pm_config.min_freq_mhz = xtal_hz / 1000000;
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
pm_config.light_sleep_enable = auto_light_sleep;
#endif
TEST_ESP_OK(esp_pm_configure(&pm_config));
}
static void ppa_srm_basic_data_correctness_check(bool auto_light_sleep)
{
const uint32_t w = 4;
const uint32_t h = 4;
@@ -305,92 +324,144 @@ TEST_CASE("ppa_srm_basic_data_correctness_check", "[PPA]")
0x0000, 0x0000, 0x0000, 0x0000
};
#if CONFIG_PM_ENABLE
enable_pm_strategy(auto_light_sleep);
#endif
ppa_client_handle_t ppa_client_handle;
ppa_client_config_t ppa_client_config = {
.oper_type = PPA_OPERATION_SRM,
.max_pending_trans_num = 1,
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
.flags.allow_pd = (auto_light_sleep ? true : false),
#endif
};
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle));
ppa_srm_oper_config_t oper_config = {
.in.buffer = in_buf,
.in.pic_w = w,
.in.pic_h = h,
.in.block_w = block_w,
.in.block_h = block_h,
.in.block_offset_x = in_block_offset_x,
.in.block_offset_y = in_block_offset_y,
.in.srm_cm = cm,
#if SOC_LIGHT_SLEEP_SUPPORTED
esp_sleep_context_t sleep_ctx;
esp_sleep_set_sleep_context(&sleep_ctx);
#endif
.out.buffer = out_buf,
.out.buffer_size = out_buf_size,
.out.pic_w = w,
.out.pic_h = h,
.out.block_offset_x = out_block_offset_x,
.out.block_offset_y = out_block_offset_y,
.out.srm_cm = cm,
// loop 3 times if we are testing PPA sleep retention feature
int cnt = (auto_light_sleep ? 3 : 1);
for (int i = 0; i < cnt; i++) {
#if SOC_LIGHT_SLEEP_SUPPORTED
sleep_ctx.sleep_request_result = ESP_FAIL; // set back to fail for new iteration
sleep_ctx.sleep_flags = 0; // clear sleep flags for new iteration
.rotation_angle = rotation,
.scale_x = scale_x,
.scale_y = scale_y,
if (auto_light_sleep) {
vTaskDelay(pdMS_TO_TICKS(1000)); // enter auto light sleep here if we are testing PPA sleep retention feature
.rgb_swap = 0,
.byte_swap = 0,
.mode = PPA_TRANS_MODE_BLOCKING,
};
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config));
// Check result
for (int i = 0; i < buf_len; i++) {
if (i % 8 == 0) {
printf("\n");
// Check if the sleep happened as expected
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
#endif
TEST_ASSERT_EQUAL(ESP_OK, sleep_ctx.sleep_request_result);
}
printf("0x%02X ", out_buf[i]);
}
printf("\n");
TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, buf_len);
#endif
ppa_srm_oper_config_t oper_config = {
.in.buffer = in_buf,
.in.pic_w = w,
.in.pic_h = h,
.in.block_w = block_w,
.in.block_h = block_h,
.in.block_offset_x = in_block_offset_x,
.in.block_offset_y = in_block_offset_y,
.in.srm_cm = cm,
.out.buffer = out_buf,
.out.buffer_size = out_buf_size,
.out.pic_w = w,
.out.pic_h = h,
.out.block_offset_x = out_block_offset_x,
.out.block_offset_y = out_block_offset_y,
.out.srm_cm = cm,
.rotation_angle = rotation,
.scale_x = scale_x,
.scale_y = scale_y,
.rgb_swap = 0,
.byte_swap = 0,
.mode = PPA_TRANS_MODE_BLOCKING,
};
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config));
// Check result
for (int i = 0; i < buf_len; i++) {
if (i % 8 == 0) {
printf("\n");
}
printf("0x%02X ", out_buf[i]);
}
printf("\n");
TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, buf_len);
#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
// Test a rgb2gray color conversion
memset(out_buf, 0, out_buf_size);
esp_cache_msync((void *)out_buf, out_buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
// Test a rgb2gray color conversion
memset(out_buf, 0, out_buf_size);
esp_cache_msync((void *)out_buf, out_buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
const uint8_t r_weight = 100;
const uint8_t g_weight = 56;
const uint8_t b_weight = 100;
TEST_ESP_OK(ppa_set_rgb2gray_formula(r_weight, g_weight, b_weight));
oper_config.out.srm_cm = PPA_SRM_COLOR_MODE_GRAY8;
oper_config.rotation_angle = PPA_SRM_ROTATION_ANGLE_0;
uint8_t out_buf_expected_gray[16] = {};
for (int i = 0; i < block_w * block_h; i++) {
const uint16_t pix = in_buf[(i / block_w + in_block_offset_y) * w + (i % block_w + in_block_offset_x)];
uint8_t _r = ((pix >> 8) & 0xF8);
uint8_t _g = ((pix >> 3) & 0xFC);
uint8_t _b = ((pix << 3) & 0xF8);
out_buf_expected_gray[(i / block_w + out_block_offset_y) * w + (i % block_w + out_block_offset_x)] = (_r * r_weight + _g * g_weight + _b * b_weight) >> 8;
}
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config));
// Check result
for (int i = 0; i < w * h; i++) {
if (i % 4 == 0) {
printf("\n");
const uint8_t r_weight = 100;
const uint8_t g_weight = 56;
const uint8_t b_weight = 100;
TEST_ESP_OK(ppa_set_rgb2gray_formula(r_weight, g_weight, b_weight));
oper_config.out.srm_cm = PPA_SRM_COLOR_MODE_GRAY8;
oper_config.rotation_angle = PPA_SRM_ROTATION_ANGLE_0;
uint8_t out_buf_expected_gray[16] = {};
for (int i = 0; i < block_w * block_h; i++) {
const uint16_t pix = in_buf[(i / block_w + in_block_offset_y) * w + (i % block_w + in_block_offset_x)];
uint8_t _r = ((pix >> 8) & 0xF8);
uint8_t _g = ((pix >> 3) & 0xFC);
uint8_t _b = ((pix << 3) & 0xF8);
out_buf_expected_gray[(i / block_w + out_block_offset_y) * w + (i % block_w + out_block_offset_x)] = (_r * r_weight + _g * g_weight + _b * b_weight) >> 8;
}
printf("0x%02X ", out_buf[i]);
}
printf("\n");
TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected_gray, (void *)out_buf, w * h);
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config));
// Check result
for (int i = 0; i < w * h; i++) {
if (i % 4 == 0) {
printf("\n");
}
printf("0x%02X ", out_buf[i]);
}
printf("\n");
TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected_gray, (void *)out_buf, w * h);
#endif // !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
memset(out_buf, 0, out_buf_size);
esp_cache_msync((void *)out_buf, out_buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
}
#if SOC_LIGHT_SLEEP_SUPPORTED
esp_sleep_set_sleep_context(NULL);
#endif
TEST_ESP_OK(ppa_unregister_client(ppa_client_handle));
#if CONFIG_PM_ENABLE
enable_pm_strategy(false);
#endif
free(out_buf);
}
TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]")
TEST_CASE("ppa_srm_basic_data_correctness_check", "[PPA]")
{
ppa_srm_basic_data_correctness_check(false);
#if CONFIG_PM_ENABLE
#if !(CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !SOC_PM_FPU_RETENTION_BY_SW) // SRM uses FPU
printf("\nTest again with auto light sleep...\n");
ppa_srm_basic_data_correctness_check(true);
#endif
#endif
}
static void ppa_blend_basic_data_correctness_check(bool auto_light_sleep)
{
const uint32_t w = 2;
const uint32_t h = 2;
@@ -423,7 +494,7 @@ TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]")
0xFF, 0xFF, 0xFF, /**/ 0x80, 0x40, 0xA0, /**/
// /*************************/
};
uint8_t in_fg_buf[64] __attribute__((aligned(64))) = {
const uint8_t in_fg_buf_template[64] __attribute__((aligned(64))) = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// /*******************************/
0xFF, 0xFF, 0xFF, 0xFF, /**/ 0x00, 0x80, 0x80, 0xC0, /**/
@@ -431,6 +502,10 @@ TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]")
// /*******************************/
[16 ... 63] = 0,
};
uint8_t *in_fg_buf = heap_caps_aligned_calloc(4, 64, sizeof(uint8_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
TEST_ASSERT_NOT_NULL(in_fg_buf);
memcpy(in_fg_buf, in_fg_buf_template, 64);
esp_cache_msync((void *)in_fg_buf, 64, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
uint8_t *out_buf = in_fg_buf;
// Expected blend output
// Alpha Blending calculation:
@@ -446,62 +521,99 @@ TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]")
// /*******************************/
};
#if CONFIG_PM_ENABLE
enable_pm_strategy(auto_light_sleep);
#endif
ppa_client_handle_t ppa_client_handle;
ppa_client_config_t ppa_client_config = {
.oper_type = PPA_OPERATION_BLEND,
.max_pending_trans_num = 1,
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
.flags.allow_pd = (auto_light_sleep ? true : false),
#endif
};
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle));
ppa_blend_oper_config_t oper_config = {
.in_bg.buffer = in_bg_buf,
.in_bg.pic_w = w,
.in_bg.pic_h = h,
.in_bg.block_w = block_w,
.in_bg.block_h = block_h,
.in_bg.block_offset_x = block_offset_x,
.in_bg.block_offset_y = block_offset_y,
.in_bg.blend_cm = in_bg_cm,
#if SOC_LIGHT_SLEEP_SUPPORTED
esp_sleep_context_t sleep_ctx;
esp_sleep_set_sleep_context(&sleep_ctx);
#endif
.in_fg.buffer = in_fg_buf,
.in_fg.pic_w = w,
.in_fg.pic_h = h,
.in_fg.block_w = block_w,
.in_fg.block_h = block_h,
.in_fg.block_offset_x = block_offset_x,
.in_fg.block_offset_y = block_offset_y,
.in_fg.blend_cm = in_fg_cm,
// loop 3 times if we are testing PPA sleep retention feature
int cnt = (auto_light_sleep ? 3 : 1);
for (int i = 0; i < cnt; i++) {
#if SOC_LIGHT_SLEEP_SUPPORTED
sleep_ctx.sleep_request_result = ESP_FAIL; // set back to fail for new iteration
sleep_ctx.sleep_flags = 0; // clear sleep flags for new iteration
.out.buffer = out_buf,
.out.buffer_size = out_buf_size,
.out.pic_w = w,
.out.pic_h = h,
.out.block_offset_x = block_offset_x,
.out.block_offset_y = block_offset_y,
.out.blend_cm = out_cm,
if (auto_light_sleep) {
vTaskDelay(pdMS_TO_TICKS(1000)); // enter auto light sleep here if we are testing PPA sleep retention feature
.bg_alpha_update_mode = PPA_ALPHA_SCALE,
.bg_alpha_scale_ratio = bg_alpha_scale_ratio,
.fg_alpha_update_mode = PPA_ALPHA_INVERT,
.bg_ck_en = false,
.fg_ck_en = false,
.mode = PPA_TRANS_MODE_BLOCKING,
};
TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &oper_config));
// Check result
for (int i = 0; i < out_buf_len; i++) {
if (i % 8 == 0) {
printf("\n");
// Check if the sleep happened as expected
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
#endif
TEST_ASSERT_EQUAL(ESP_OK, sleep_ctx.sleep_request_result);
}
printf("0x%02X ", out_buf[i]);
#endif
ppa_blend_oper_config_t oper_config = {
.in_bg.buffer = in_bg_buf,
.in_bg.pic_w = w,
.in_bg.pic_h = h,
.in_bg.block_w = block_w,
.in_bg.block_h = block_h,
.in_bg.block_offset_x = block_offset_x,
.in_bg.block_offset_y = block_offset_y,
.in_bg.blend_cm = in_bg_cm,
.in_fg.buffer = in_fg_buf,
.in_fg.pic_w = w,
.in_fg.pic_h = h,
.in_fg.block_w = block_w,
.in_fg.block_h = block_h,
.in_fg.block_offset_x = block_offset_x,
.in_fg.block_offset_y = block_offset_y,
.in_fg.blend_cm = in_fg_cm,
.out.buffer = out_buf,
.out.buffer_size = out_buf_size,
.out.pic_w = w,
.out.pic_h = h,
.out.block_offset_x = block_offset_x,
.out.block_offset_y = block_offset_y,
.out.blend_cm = out_cm,
.bg_alpha_update_mode = PPA_ALPHA_SCALE,
.bg_alpha_scale_ratio = bg_alpha_scale_ratio,
.fg_alpha_update_mode = PPA_ALPHA_INVERT,
.bg_ck_en = false,
.fg_ck_en = false,
.mode = PPA_TRANS_MODE_BLOCKING,
};
TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &oper_config));
// Check result
for (int i = 0; i < out_buf_len; i++) {
if (i % 8 == 0) {
printf("\n");
}
printf("0x%02X ", out_buf[i]);
}
printf("\n");
TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, out_buf_len);
memcpy(in_fg_buf, in_fg_buf_template, 64);
esp_cache_msync((void *)in_fg_buf, 64, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
}
printf("\n");
TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, out_buf_len);
#if SOC_LIGHT_SLEEP_SUPPORTED
esp_sleep_set_sleep_context(NULL);
#endif
#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
// Test YUV422/YUV420 blend
@@ -580,9 +692,26 @@ TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]")
#endif // !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
TEST_ESP_OK(ppa_unregister_client(ppa_client_handle));
#if CONFIG_PM_ENABLE
enable_pm_strategy(false);
#endif
free(in_fg_buf);
}
TEST_CASE("ppa_fill_basic_data_correctness_check", "[PPA]")
TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]")
{
ppa_blend_basic_data_correctness_check(false);
#if CONFIG_PM_ENABLE
#if !(CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !SOC_PM_FPU_RETENTION_BY_SW) // Blend uses FPU
printf("\nTest again with auto light sleep...\n");
ppa_blend_basic_data_correctness_check(true);
#endif
#endif
}
static void ppa_fill_basic_data_correctness_check(bool auto_light_sleep)
{
const uint32_t w = 80;
const uint32_t h = 120;
@@ -605,57 +734,110 @@ TEST_CASE("ppa_fill_basic_data_correctness_check", "[PPA]")
memset(out_buf, 0xFF, out_buf_len);
#if CONFIG_PM_ENABLE
enable_pm_strategy(auto_light_sleep);
#endif
ppa_client_handle_t ppa_client_handle;
ppa_client_config_t ppa_client_config = {
.oper_type = PPA_OPERATION_FILL,
.max_pending_trans_num = 1,
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
.flags.allow_pd = (auto_light_sleep ? true : false),
#endif
};
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle));
ppa_fill_oper_config_t oper_config = {
.out.buffer = out_buf,
.out.buffer_size = out_buf_size,
.out.pic_w = w,
.out.pic_h = h,
.out.block_offset_x = block_offset_x,
.out.block_offset_y = block_offset_y,
.out.fill_cm = out_cm,
#if SOC_LIGHT_SLEEP_SUPPORTED
esp_sleep_context_t sleep_ctx;
esp_sleep_set_sleep_context(&sleep_ctx);
#endif
.fill_block_w = block_w,
.fill_block_h = block_h,
.fill_argb_color = fill_color,
// loop 3 times if we are testing PPA sleep retention feature
int cnt = (auto_light_sleep ? 3 : 1);
for (int i = 0; i < cnt; i++) {
#if SOC_LIGHT_SLEEP_SUPPORTED
sleep_ctx.sleep_request_result = ESP_FAIL; // set back to fail for new iteration
sleep_ctx.sleep_flags = 0; // clear sleep flags for new iteration
.mode = PPA_TRANS_MODE_BLOCKING,
};
if (auto_light_sleep) {
vTaskDelay(pdMS_TO_TICKS(1000)); // enter auto light sleep here if we are testing PPA sleep retention feature
TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config));
// Check if the sleep happened as expected
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
#endif
TEST_ASSERT_EQUAL(ESP_OK, sleep_ctx.sleep_request_result);
}
#endif
// Check result
const color_pixel_rgb565_data_t fill_pixel_expected = {.r = fill_color.r >> 3,
.g = fill_color.g >> 2,
.b = fill_color.b >> 3,
};
TEST_ASSERT_EACH_EQUAL_UINT16(fill_pixel_expected.val, (void *)((uint32_t)out_buf + w * block_offset_y * out_pixel_depth / 8), block_w * block_h);
ppa_fill_oper_config_t oper_config = {
.out.buffer = out_buf,
.out.buffer_size = out_buf_size,
.out.pic_w = w,
.out.pic_h = h,
.out.block_offset_x = block_offset_x,
.out.block_offset_y = block_offset_y,
.out.fill_cm = out_cm,
.fill_block_w = block_w,
.fill_block_h = block_h,
.fill_argb_color = fill_color,
.mode = PPA_TRANS_MODE_BLOCKING,
};
TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config));
// Check result
color_pixel_rgb565_data_t fill_pixel_expected = {};
fill_pixel_expected.r = fill_color.r >> 3;
fill_pixel_expected.g = fill_color.g >> 2;
fill_pixel_expected.b = fill_color.b >> 3;
TEST_ASSERT_EACH_EQUAL_UINT16(fill_pixel_expected.val, (void *)((uint32_t)out_buf + w * block_offset_y * out_pixel_depth / 8), block_w * block_h);
#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
// Test a yuv color fill
oper_config.out.fill_cm = PPA_FILL_COLOR_MODE_YUV422_UYVY; // output YUV422 is with UYVY packed order
const color_macroblock_yuv_data_t fill_yuv_color = {.y = 0xFF, .u = 0x55, .v = 0xAA};
oper_config.fill_yuv_color = fill_yuv_color;
out_pixel_format.color_type_id = PPA_FILL_COLOR_MODE_YUV422_UYVY;
out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); // bits
TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config));
// Test a yuv color fill
oper_config.out.fill_cm = PPA_FILL_COLOR_MODE_YUV422_UYVY; // output YUV422 is with UYVY packed order
color_macroblock_yuv_data_t fill_yuv_color = {};
fill_yuv_color.y = 0xFF;
fill_yuv_color.u = 0x55;
fill_yuv_color.v = 0xAA;
oper_config.fill_yuv_color = fill_yuv_color;
out_pixel_format.color_type_id = PPA_FILL_COLOR_MODE_YUV422_UYVY;
out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); // bits
TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config));
// Check result (2 pixels per macro pixel)
const uint32_t fill_pixel_expected_yuv422 = ((fill_yuv_color.y << 24) | (fill_yuv_color.v << 16) | (fill_yuv_color.y << 8) | (fill_yuv_color.u));
TEST_ASSERT_EACH_EQUAL_UINT32(fill_pixel_expected_yuv422, (void *)((uint32_t)out_buf + w * block_offset_y * out_pixel_depth / 8), block_w * block_h / 2);
// Check result (2 pixels per macro pixel)
const uint32_t fill_pixel_expected_yuv422 = ((fill_yuv_color.y << 24) | (fill_yuv_color.v << 16) | (fill_yuv_color.y << 8) | (fill_yuv_color.u));
TEST_ASSERT_EACH_EQUAL_UINT32(fill_pixel_expected_yuv422, (void *)((uint32_t)out_buf + w * block_offset_y * out_pixel_depth / 8), block_w * block_h / 2);
#endif // !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3)
memset(out_buf, 0xFF, out_buf_size);
esp_cache_msync((void *)out_buf, out_buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
}
#if SOC_LIGHT_SLEEP_SUPPORTED
esp_sleep_set_sleep_context(NULL);
#endif
TEST_ESP_OK(ppa_unregister_client(ppa_client_handle));
#if CONFIG_PM_ENABLE
enable_pm_strategy(false);
#endif
free(out_buf);
}
TEST_CASE("ppa_fill_basic_data_correctness_check", "[PPA]")
{
ppa_fill_basic_data_correctness_check(false);
#if CONFIG_PM_ENABLE
printf("\nTest again with auto light sleep...\n");
ppa_fill_basic_data_correctness_check(true);
#endif
}
/* All performance tests are tested under the following situations:
* - Testing PPA speed where in_buffer(s) and out_buffer all located in PSRAM
* - Only 2D-DMA is using PSRAM
@@ -1,6 +1,7 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_PM_DFS_INIT_AUTO=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
@@ -1,3 +1,5 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_ESP_SLEEP_DEBUG=y
+45
View File
@@ -24,6 +24,7 @@
#include "soc/dma2d_channel.h"
#include "soc/dma2d_periph.h"
#include "esp_bit_defs.h"
#include "esp_private/sleep_retention.h"
/**
* The 2D-DMA driver is designed with a pool & client model + queue design pattern.
@@ -349,6 +350,17 @@ static void dma2d_default_isr(void *args)
}
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
static esp_err_t dma2d_create_sleep_retention_link_cb(void *arg)
{
sleep_retention_module_t module = dma2d_reg_retention_info.module;
esp_err_t err = sleep_retention_entries_create(dma2d_reg_retention_info.regdma_entry_array,
dma2d_reg_retention_info.array_size,
REGDMA_LINK_PRI_DMA2D, module);
return err;
}
#endif
esp_err_t dma2d_acquire_pool(const dma2d_pool_config_t *config, dma2d_pool_handle_t *ret_pool)
{
esp_err_t ret = ESP_OK;
@@ -403,6 +415,29 @@ esp_err_t dma2d_acquire_pool(const dma2d_pool_config_t *config, dma2d_pool_handl
dma2d_hal_init(&pre_alloc_group->hal, group_id); // initialize HAL context
// Enable 2D-DMA module clock
dma2d_ll_hw_enable(s_platform.groups[group_id]->hal.dev, true);
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
// acquire sleep retention
sleep_retention_module_t module = dma2d_reg_retention_info.module;
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = {
.handle = dma2d_create_sleep_retention_link_cb,
.arg = NULL,
},
},
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
};
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
// even though the sleep retention module init failed, DMA2D driver should still work, so just warning here
ESP_LOGW(TAG, "init sleep retention failed, power domain may be turned off during sleep");
} else {
if (sleep_retention_module_allocate(module) != ESP_OK) {
ESP_LOGW(TAG, "fail to allocate retention link list");
// don't call sleep_retention_module_deinit here, otherwise DMA2D peripheral may be powered off during sleep
}
}
#endif
} else {
ret = ESP_ERR_NO_MEM;
free(pre_alloc_tx_channels);
@@ -506,6 +541,16 @@ esp_err_t dma2d_release_pool(dma2d_pool_handle_t dma2d_pool)
PERIPH_RCC_ATOMIC() {
dma2d_ll_enable_bus_clock(group_id, false);
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
sleep_retention_module_t module = dma2d_reg_retention_info.module;
if (sleep_retention_is_module_created(module)) {
sleep_retention_module_free(module);
}
if (sleep_retention_is_module_inited(module)) {
sleep_retention_module_deinit(module);
}
#endif
}
if (do_deinitialize) {
@@ -294,6 +294,14 @@ bool peripheral_domain_pd_allowed(void)
mask.bitmap[SLEEP_RETENTION_MODULE_MCPWM0 >> 5] |= BIT(SLEEP_RETENTION_MODULE_MCPWM0 % 32);
#endif
#if SOC_DMA2D_SUPPORTED
mask.bitmap[SLEEP_RETENTION_MODULE_DMA2D >> 5] |= BIT(SLEEP_RETENTION_MODULE_DMA2D % 32);
#endif
#if SOC_PPA_SUPPORTED
mask.bitmap[SLEEP_RETENTION_MODULE_PPA >> 5] |= BIT(SLEEP_RETENTION_MODULE_PPA % 32);
#endif
const sleep_retention_module_bitmap_t peripheral_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask);
const sleep_retention_module_bitmap_t peripheral_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask);
return sleep_retention_module_bitmap_eq(peripheral_domain_inited_modules, peripheral_domain_created_modules);
@@ -700,3 +700,7 @@ TEST_CASE("DMA2D_M2M_2D_window", "[DMA2D]")
TEST_ESP_OK(dma2d_m2m_deinit());
}
// Note:
// Sleep retention functionality test is not covered yet, since all basic test cases can survive with 2D-DMA registers reset to default value.
// It shall be tested when arbiter feature is supported and its test case is added.
@@ -92,7 +92,7 @@ extern "C" {
* @param group_id Group ID
* @param enable True to enable; false to disable
*/
static inline void dma2d_ll_enable_bus_clock(int group_id, bool enable)
static inline void _dma2d_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
HP_SYS_CLKRST.soc_clk_ctrl1.reg_dma2d_sys_clk_en = enable;
@@ -100,14 +100,14 @@ static inline void dma2d_ll_enable_bus_clock(int group_id, bool enable)
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define dma2d_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; dma2d_ll_enable_bus_clock(__VA_ARGS__)
#define dma2d_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _dma2d_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the 2D-DMA module
*
* @param group_id Group ID
*/
static inline void dma2d_ll_reset_register(int group_id)
static inline void _dma2d_ll_reset_register(int group_id)
{
(void)group_id;
HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_dma2d = 1;
@@ -116,7 +116,7 @@ static inline void dma2d_ll_reset_register(int group_id)
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define dma2d_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; dma2d_ll_reset_register(__VA_ARGS__)
#define dma2d_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _dma2d_ll_reset_register(__VA_ARGS__)
/**
* @brief Check if the bus clock is enabled for the DMA module
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -53,19 +53,19 @@ typedef enum {
*
* @param enable Set true to enable, false to disable
*/
static inline void ppa_ll_enable_bus_clock(bool enable)
static inline void _ppa_ll_enable_bus_clock(bool enable)
{
HP_SYS_CLKRST.soc_clk_ctrl1.reg_ppa_sys_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define ppa_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; ppa_ll_enable_bus_clock(__VA_ARGS__)
#define ppa_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _ppa_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the PPA module
*/
static inline void ppa_ll_reset_register(void)
static inline void _ppa_ll_reset_register(void)
{
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_ppa = 1;
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_ppa = 0;
@@ -73,7 +73,7 @@ static inline void ppa_ll_reset_register(void)
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define ppa_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; ppa_ll_reset_register(__VA_ARGS__)
#define ppa_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _ppa_ll_reset_register(__VA_ARGS__)
/**
* @brief Configure the RGB888 to GRAY8 color conversion coefficients for SRM and Blending (excluding Fill)
+4
View File
@@ -68,6 +68,10 @@ if(CONFIG_SOC_DMA2D_SUPPORTED)
list(APPEND srcs "${target_folder}/dma2d_periph.c")
endif()
if(CONFIG_SOC_PPA_SUPPORTED)
list(APPEND srcs "${target_folder}/ppa_periph.c")
endif()
if(CONFIG_SOC_GPSPI_SUPPORTED)
list(APPEND srcs "${target_folder}/spi_periph.c")
endif()
+31 -1
View File
@@ -1,10 +1,11 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/dma2d_periph.h"
#include "soc/dma2d_reg.h"
#include "soc/interrupts.h"
const dma2d_signal_conn_t dma2d_periph_signals = {
@@ -24,3 +25,32 @@ const dma2d_signal_conn_t dma2d_periph_signals = {
}
}
};
/** DMA2D Registers to be saved during sleep retention
*
* DMA2D driver is implemented in the way that channels are used as a pool,
* therefore, only general registers are needed to be saved during sleep retention.
*
* DMA2D_RST_CONF_REG,
* DMA2D_INTR_MEM_START_ADDR_REG, DMA2D_INTR_MEM_END_ADDR_REG, DMA2D_EXTR_MEM_START_ADDR_REG, DMA2D_EXTR_MEM_END_ADDR_REG
* DMA2D_OUT_ARB_CONFIG_REG, DMA2D_IN_ARB_CONFIG_REG
*/
#define DMA2D_RETENTION_REGS_CNT 7
#define DMA2D_RETENTION_REGS_BASE DMA2D_RST_CONF_REG
static const uint32_t dma2d_regs_map[4] = {0x7f, 0x0, 0x0, 0x0};
static const regdma_entries_config_t dma2d_regdma_entries[] = {
[0] = {
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_DMA2D_LINK(0x00),
DMA2D_RETENTION_REGS_BASE, DMA2D_RETENTION_REGS_BASE,
DMA2D_RETENTION_REGS_CNT, 0, 0,
dma2d_regs_map[0], dma2d_regs_map[1],
dma2d_regs_map[2], dma2d_regs_map[3]),
.owner = ENTRY(0),
},
};
const dma2d_reg_retention_info_t dma2d_reg_retention_info = {
.module = SLEEP_RETENTION_MODULE_DMA2D,
.regdma_entry_array = dma2d_regdma_entries,
.array_size = ARRAY_SIZE(dma2d_regdma_entries),
};
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -60,6 +60,8 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_MCPWM0 = 34,
SLEEP_RETENTION_MODULE_MCPWM1 = 35,
SLEEP_RETENTION_MODULE_PCNT0 = 36,
SLEEP_RETENTION_MODULE_DMA2D = 41,
SLEEP_RETENTION_MODULE_PPA = 42,
SLEEP_RETENTION_MODULE_MAX = SOC_PM_RETENTION_MODULE_NUM - 1
} periph_retention_module_t;
@@ -102,6 +104,8 @@ typedef enum periph_retention_module {
: ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \
: ((m) == SLEEP_RETENTION_MODULE_MCPWM1) ? true \
: ((m) == SLEEP_RETENTION_MODULE_PCNT0) ? true \
: ((m) == SLEEP_RETENTION_MODULE_DMA2D) ? true \
: ((m) == SLEEP_RETENTION_MODULE_PPA) ? true \
: false)
#ifdef __cplusplus
+38
View File
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/ppa_periph.h"
#include "soc/ppa_reg.h"
/** PPA Registers to be saved during sleep retention
*
* For CLUT mem, we shall choose not to power down the CLUT mem domain; Otherwise, there are two blocks of memory that needs to be restored by writing to mem addr directly.
* Since PPA driver is operation based, most of the registers are configured per operation, so no need to save/restore.
*
* PPA_CLUT_CONF_REG,
* PPA_INT_ENA_REG,
* PPA_SR_MEM_PD_REG, PPA_REG_CONF_REG, PPA_SRAM_CTRL_REG,
* PPA_RGB2GRAY_REG (> rev3 only, but ok to include it for < rev3 chips)
*/
#define PPA_RETENTION_REGS_CNT 6
#define PPA_RETENTION_REGS_BASE PPA_CLUT_CONF_REG
static const uint32_t ppa_regs_map[4] = {0x1800009, 0x9, 0x0, 0x0};
static const regdma_entries_config_t ppa_regdma_entries[] = {
[0] = {
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PPA_LINK(0x00),
PPA_RETENTION_REGS_BASE, PPA_RETENTION_REGS_BASE,
PPA_RETENTION_REGS_CNT, 0, 0,
ppa_regs_map[0], ppa_regs_map[1],
ppa_regs_map[2], ppa_regs_map[3]),
.owner = ENTRY(0),
},
};
const ppa_reg_retention_info_t ppa_reg_retention_info = {
.module = SLEEP_RETENTION_MODULE_PPA,
.regdma_entry_array = ppa_regdma_entries,
.array_size = ARRAY_SIZE(ppa_regdma_entries),
};
@@ -26,8 +26,13 @@
#include "soc/pvt_reg.h"
/* Interrupt Matrix Registers Context */
#if (CONFIG_ESP_REV_MIN_FULL < 300)
#define N_REGS_INTR_CORE0() (((INTERRUPT_CORE0_CLOCK_GATE_REG - DR_REG_INTERRUPT_CORE0_BASE) / 4) + 1)
#define N_REGS_INTR_CORE1() (((INTERRUPT_CORE1_CLOCK_GATE_REG - DR_REG_INTERRUPT_CORE1_BASE) / 4) + 1)
#else
#define N_REGS_INTR_CORE0() (((INTERRUPT_CORE0_INTR_SIG_IDX_ASSERT_IN_SEC_REG - DR_REG_INTERRUPT_CORE0_BASE) / 4) + 1)
#define N_REGS_INTR_CORE1() (((INTERRUPT_CORE1_INTR_SIG_IDX_ASSERT_IN_SEC_REG - DR_REG_INTERRUPT_CORE1_BASE) / 4) + 1)
#endif
const regdma_entries_config_t intr_matrix_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_INTMTX_LINK(0x00), DR_REG_INTERRUPT_CORE0_BASE, DR_REG_INTERRUPT_CORE0_BASE, N_REGS_INTR_CORE0(), 0, 0), .owner = ENTRY(0) }, /* intr matrix */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_INTMTX_LINK(0x01), DR_REG_INTERRUPT_CORE1_BASE, DR_REG_INTERRUPT_CORE1_BASE, N_REGS_INTR_CORE1(), 0, 0), .owner = ENTRY(0) } /* intr matrix */
+16 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,6 +9,11 @@
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_PAU_SUPPORTED
#include "soc/regdma.h"
#include "soc/retention_periph_defs.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -22,6 +27,16 @@ typedef struct {
} dma2d_signal_conn_t;
extern const dma2d_signal_conn_t dma2d_periph_signals;
#if SOC_LIGHT_SLEEP_SUPPORTED
typedef struct {
const periph_retention_module_t module;
const regdma_entries_config_t *regdma_entry_array;
uint32_t array_size;
} dma2d_reg_retention_info_t;
extern const dma2d_reg_retention_info_t dma2d_reg_retention_info;
#endif
#endif
#ifdef __cplusplus
+33
View File
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_PAU_SUPPORTED
#include "soc/regdma.h"
#include "soc/retention_periph_defs.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_PPA_SUPPORTED
#if SOC_LIGHT_SLEEP_SUPPORTED
typedef struct {
const periph_retention_module_t module;
const regdma_entries_config_t *regdma_entry_array;
uint32_t array_size;
} ppa_reg_retention_info_t;
extern const ppa_reg_retention_info_t ppa_reg_retention_info;
#endif
#endif
#ifdef __cplusplus
}
#endif
+5 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -64,6 +64,8 @@ extern "C" {
#define REGDMA_LEDC_LINK(_pri) ((0x24 << 8) | _pri)
#define REGDMA_PCNT_LINK(_pri) ((0x25 << 8) | _pri)
#define REGDMA_MCPWM_LINK(_pri) ((0x26 << 8) | _pri)
#define REGDMA_PPA_LINK(_pri) ((0x2B << 8) | _pri)
#define REGDMA_DMA2D_LINK(_pri) ((0x2C << 8) | _pri)
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
@@ -91,6 +93,8 @@ extern "C" {
#define REGDMA_LINK_PRI_GPSPI REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_LEDC REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_MCPWM REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_PPA REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_DMA2D REGDMA_LINK_PRI_GENERAL_PERIPH
typedef enum {
REGDMA_LINK_PRI_0 = 0,