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

This commit is contained in:
Song Ruo Jing
2026-06-15 15:45:07 +08:00
parent 67fdf46105
commit 14d8570163
26 changed files with 690 additions and 155 deletions
+70
View File
@@ -34,6 +34,7 @@
#include "hal/color_hal.h"
#include "hal/color_types.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/sleep_retention.h"
#include "esp_efuse.h"
#include "soc/soc_caps.h"
@@ -55,6 +56,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;
@@ -187,6 +207,40 @@ 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,
},
},
.attribute = SLEEP_RETENTION_MODULE_ATTR_ATTACH,
.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 (sleep_retention_module_attach(module) != ESP_OK) {
ESP_LOGW(TAG, "attach retention module failed, power domain can't turn off");
}
}
}
} 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:
@@ -247,6 +301,20 @@ 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_attached(module)) {
sleep_retention_module_detach(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;
@@ -288,11 +356,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");
}
+20 -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
*/
@@ -18,6 +18,8 @@
#include "hal/ppa_types.h"
#include "hal/ppa_hal.h"
#include "esp_pm.h"
#include "soc/soc_caps.h"
#include "soc/regdma.h"
#ifdef __cplusplus
extern "C" {
@@ -81,6 +83,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 *************************************/
@@ -247,8 +252,22 @@ struct ppa_platform_t {
size_t int_mem_align; // Alignment requirement for the internal outgoing buffer to satisfy cache line size
size_t ext_mem_align; // Alignment requirement for the external outgoing buffer 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
};
#if SOC_PAU_SUPPORTED
#include "soc/retention_periph_defs.h"
typedef struct {
const periph_retention_module_t module;
const regdma_entries_config_t *regdma_entry_array;
uint32_t array_size;
} ppa_retention_desc_t;
extern const ppa_retention_desc_t ppa_reg_retention_info;
#endif // SOC_PAU_SUPPORTED
#ifdef __cplusplus
}
#endif