mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
Merge branch 'feature/add_asrc_sleep_retention' into 'master'
feat(asrc): Add sleep retention See merge request espressif/esp-idf!50719
This commit is contained in:
@@ -8,8 +8,13 @@ set(srcs)
|
||||
# ASRC related source files
|
||||
if(CONFIG_SOC_ASRC_SUPPORTED)
|
||||
list(APPEND srcs "asrc_adapter.c")
|
||||
if(CONFIG_SOC_PAU_SUPPORTED)
|
||||
list(APPEND srcs "${target}/asrc_retention.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
REQUIRES esp_hal_asrc esp_driver_dma esp_mm)
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
REQUIRES esp_hal_asrc esp_driver_dma esp_mm
|
||||
PRIV_REQUIRES esp_hw_support esp_pm)
|
||||
|
||||
14
components/esp_asrc_adapter/Kconfig
Normal file
14
components/esp_asrc_adapter/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
menu "ESP-ASRC Configurations"
|
||||
depends on SOC_ASRC_SUPPORTED
|
||||
|
||||
config ASRC_ALLOW_PD
|
||||
bool "Allow power down of ASRC in light sleep"
|
||||
default n
|
||||
depends on PM_ENABLE && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
help
|
||||
If enabled, the ASRC driver will backup/restore ASRC registers before/after
|
||||
entering/exiting light sleep via the sleep retention framework.
|
||||
By this approach, the system can power off ASRC's power domain (TOP PD).
|
||||
This can save power, but at the expense of more RAM being consumed.
|
||||
|
||||
endmenu
|
||||
@@ -16,11 +16,23 @@
|
||||
#include "esp_cache.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "asrc_adapter.h"
|
||||
#include "sys/lock.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "asrc_adapter_priv.h"
|
||||
|
||||
#define TAG "ASRC_ADAPTER"
|
||||
#if ASRC_USE_RETENTION_LINK
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif /* ASRC_USE_RETENTION_LINK */
|
||||
|
||||
#define TAG "ASRC_ADAPTER"
|
||||
#define ASRC_HW_GDMA_DESC_BUFFER_MAX_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_16B_ALIGNED
|
||||
|
||||
#if ASRC_USE_RETENTION_LINK
|
||||
/* Note: sleep retention APIs use OS locks, so use a lock rather than a light-weight critical section */
|
||||
static _lock_t s_asrc_sleep_retention_lock;
|
||||
static uint8_t s_asrc_retention_ref_count;
|
||||
#endif /* ASRC_USE_RETENTION_LINK */
|
||||
|
||||
static bool IRAM_ATTR asrc_hw_rx_eof(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
|
||||
{
|
||||
portBASE_TYPE higher_priority_task_awoken = pdFALSE;
|
||||
@@ -29,6 +41,79 @@ static bool IRAM_ATTR asrc_hw_rx_eof(gdma_channel_handle_t dma_chan, gdma_event_
|
||||
return higher_priority_task_awoken;
|
||||
}
|
||||
|
||||
#if ASRC_USE_RETENTION_LINK
|
||||
static esp_err_t s_asrc_sleep_retention_init_cb(void *arg)
|
||||
{
|
||||
esp_err_t ret = sleep_retention_entries_create(asrc_reg_retention_info[0].entry_array,
|
||||
asrc_reg_retention_info[0].array_size,
|
||||
REGDMA_LINK_PRI_ASRC, asrc_reg_retention_info[0].retention_module);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "failed to allocate mem for sleep retention");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asrc_acquire_sleep_retention(void)
|
||||
{
|
||||
sleep_retention_module_t module = asrc_reg_retention_info[0].retention_module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = s_asrc_sleep_retention_init_cb,
|
||||
.arg = NULL,
|
||||
},
|
||||
},
|
||||
.attribute = SLEEP_RETENTION_MODULE_ATTR_ATTACH,
|
||||
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM),
|
||||
};
|
||||
|
||||
_lock_acquire(&s_asrc_sleep_retention_lock);
|
||||
if (s_asrc_retention_ref_count == 0) {
|
||||
esp_err_t err = sleep_retention_module_init(module, &init_param);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "init sleep retention failed, ASRC configuration may be lost after sleep wakeup");
|
||||
} else {
|
||||
#if defined(CONFIG_ASRC_ALLOW_PD) && CONFIG_ASRC_ALLOW_PD
|
||||
err = sleep_retention_module_allocate(module);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "create retention module failed, power domain can't turn off");
|
||||
/* don't call sleep_retention_module_deinit here, otherwise ASRC 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");
|
||||
}
|
||||
#endif /* CONFIG_ASRC_ALLOW_PD */
|
||||
}
|
||||
}
|
||||
s_asrc_retention_ref_count++;
|
||||
_lock_release(&s_asrc_sleep_retention_lock);
|
||||
}
|
||||
|
||||
static void asrc_release_sleep_retention(void)
|
||||
{
|
||||
sleep_retention_module_t module = asrc_reg_retention_info[0].retention_module;
|
||||
|
||||
_lock_acquire(&s_asrc_sleep_retention_lock);
|
||||
if (s_asrc_retention_ref_count == 0) {
|
||||
_lock_release(&s_asrc_sleep_retention_lock);
|
||||
return;
|
||||
}
|
||||
s_asrc_retention_ref_count--;
|
||||
if (s_asrc_retention_ref_count == 0) {
|
||||
#if defined(CONFIG_ASRC_ALLOW_PD) && CONFIG_ASRC_ALLOW_PD
|
||||
if (sleep_retention_module_detach(module) == ESP_OK) {
|
||||
if (sleep_retention_module_free(module) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "fail to free the retention link list");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "fail to detach the retention link list");
|
||||
}
|
||||
#endif /* CONFIG_ASRC_ALLOW_PD */
|
||||
if (sleep_retention_module_deinit(module) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "fail to deinit the retention module");
|
||||
}
|
||||
}
|
||||
_lock_release(&s_asrc_sleep_retention_lock);
|
||||
}
|
||||
#endif /* ASRC_USE_RETENTION_LINK */
|
||||
|
||||
esp_err_t asrc_hw_gdma_create_channel(int asrc_idx, void *user_data, uint16_t max_data_burst_size,
|
||||
asrc_hw_gdma_channel_handle_t *dma_tx_chan, asrc_hw_gdma_channel_handle_t *dma_rx_chan)
|
||||
{
|
||||
@@ -65,6 +150,10 @@ esp_err_t asrc_hw_gdma_create_channel(int asrc_idx, void *user_data, uint16_t ma
|
||||
ESP_GOTO_ON_ERROR(gdma_config_transfer(dma_tx, &transfer_config), cleanup, TAG, "Fail to config tx transfer");
|
||||
gdma_rx_event_callbacks_t cb = {.on_recv_eof = asrc_hw_rx_eof};
|
||||
ESP_GOTO_ON_ERROR(gdma_register_rx_event_callbacks(dma_rx, &cb, user_data), cleanup, TAG, "Fail to register rx event callbacks");
|
||||
#if ASRC_USE_RETENTION_LINK
|
||||
/* Register retention while creating channel, same style as GDMA */
|
||||
asrc_acquire_sleep_retention();
|
||||
#endif /* ASRC_USE_RETENTION_LINK */
|
||||
*dma_tx_chan = dma_tx;
|
||||
*dma_rx_chan = dma_rx;
|
||||
return ESP_OK;
|
||||
@@ -172,6 +261,11 @@ void asrc_hw_gdma_destroy_channel(asrc_hw_gdma_channel_handle_t dma_tx_chan, asr
|
||||
gdma_disconnect(dma_rx_chan_handle);
|
||||
gdma_del_channel(dma_rx_chan_handle);
|
||||
}
|
||||
#if ASRC_USE_RETENTION_LINK
|
||||
if (dma_tx_chan != NULL || dma_rx_chan != NULL) {
|
||||
asrc_release_sleep_retention();
|
||||
}
|
||||
#endif /* ASRC_USE_RETENTION_LINK */
|
||||
}
|
||||
|
||||
esp_err_t asrc_hw_get_buffer_alignment(uint32_t heap_caps, size_t *out_alignment)
|
||||
|
||||
42
components/esp_asrc_adapter/asrc_adapter_priv.h
Normal file
42
components/esp_asrc_adapter/asrc_adapter_priv.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "asrc_adapter.h"
|
||||
|
||||
#if SOC_PAU_SUPPORTED
|
||||
#include "soc/regdma.h"
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif /* SOC_PAU_SUPPORTED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#if SOC_PAU_SUPPORTED
|
||||
/**
|
||||
* @brief Use retention link only when PM is enabled and peripheral power-down in light sleep is allowed
|
||||
*/
|
||||
#define ASRC_USE_RETENTION_LINK (CONFIG_PM_ENABLE && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
|
||||
|
||||
/**
|
||||
* @brief ASRC register sleep retention information
|
||||
*/
|
||||
typedef struct {
|
||||
const periph_retention_module_t retention_module;
|
||||
const regdma_entries_config_t *entry_array;
|
||||
uint32_t array_size;
|
||||
} asrc_reg_retention_info_t;
|
||||
|
||||
extern const asrc_reg_retention_info_t asrc_reg_retention_info[1];
|
||||
#endif /* SOC_PAU_SUPPORTED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
42
components/esp_asrc_adapter/esp32h4/asrc_retention.c
Normal file
42
components/esp_asrc_adapter/esp32h4/asrc_retention.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "soc/asrc_reg.h"
|
||||
#include "asrc_adapter_priv.h"
|
||||
|
||||
/**
|
||||
* ASRC Registers to be saved during sleep retention
|
||||
*
|
||||
* Retained R/W registers per channel (WT/RO registers excluded):
|
||||
* CHNL0: CFG0(0x00) CFG1(0x04) CFG2(0x08) CFG4(0x10) CFG5(0x14) CFG6(0x18) INT_ENA(0x28)
|
||||
* CHNL1: CFG0(0x3c) CFG1(0x40) CFG2(0x44) CFG4(0x4c) CFG5(0x50) CFG6(0x54) INT_ENA(0x64)
|
||||
*
|
||||
*/
|
||||
#define ASRC_RETENTION_REGS_CNT 14
|
||||
#define ASRC_RETENTION_REGS_BASE (DR_REG_ASRC_BASE + 0x0)
|
||||
|
||||
static const uint32_t asrc_regs_map[4] = {0x023B8477, 0x0, 0x0, 0x0};
|
||||
static const regdma_entries_config_t asrc_regdma_entries[] = {
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_ASRC_LINK(0x00),
|
||||
ASRC_RETENTION_REGS_BASE, ASRC_RETENTION_REGS_BASE,
|
||||
ASRC_RETENTION_REGS_CNT, 0, 0,
|
||||
asrc_regs_map[0], asrc_regs_map[1],
|
||||
asrc_regs_map[2], asrc_regs_map[3]),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
};
|
||||
|
||||
const asrc_reg_retention_info_t asrc_reg_retention_info[1] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_ASRC,
|
||||
.entry_array = asrc_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(asrc_regdma_entries),
|
||||
},
|
||||
};
|
||||
42
components/esp_asrc_adapter/esp32s31/asrc_retention.c
Normal file
42
components/esp_asrc_adapter/esp32s31/asrc_retention.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "soc/asrc_reg.h"
|
||||
#include "asrc_adapter_priv.h"
|
||||
|
||||
/**
|
||||
* ASRC Registers to be saved during sleep retention
|
||||
*
|
||||
* Retained R/W registers per channel (WT/RO registers excluded):
|
||||
* CHNL0: CFG0(0x00) CFG1(0x04) CFG2(0x08) CFG4(0x10) CFG5(0x14) CFG6(0x18) INT_ENA(0x28)
|
||||
* CHNL1: CFG0(0x3c) CFG1(0x40) CFG2(0x44) CFG4(0x4c) CFG5(0x50) CFG6(0x54) INT_ENA(0x64)
|
||||
*
|
||||
*/
|
||||
#define ASRC_RETENTION_REGS_CNT 14
|
||||
#define ASRC_RETENTION_REGS_BASE (DR_REG_ASRC_BASE + 0x0)
|
||||
|
||||
static const uint32_t asrc_regs_map[4] = {0x023B8477, 0x0, 0x0, 0x0};
|
||||
static const regdma_entries_config_t asrc_regdma_entries[] = {
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_ASRC_LINK(0x00),
|
||||
ASRC_RETENTION_REGS_BASE, ASRC_RETENTION_REGS_BASE,
|
||||
ASRC_RETENTION_REGS_CNT, 0, 0,
|
||||
asrc_regs_map[0], asrc_regs_map[1],
|
||||
asrc_regs_map[2], asrc_regs_map[3]),
|
||||
.owner = ENTRY(0) | ENTRY(2),
|
||||
},
|
||||
};
|
||||
|
||||
const asrc_reg_retention_info_t asrc_reg_retention_info[1] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_ASRC,
|
||||
.entry_array = asrc_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(asrc_regdma_entries),
|
||||
},
|
||||
};
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -82,6 +82,9 @@ bool peripheral_domain_pd_allowed(void)
|
||||
// ESP32H4 supports SDM sleep retention
|
||||
RETENTION_MODULE_BITMAP_SET(&mask, SLEEP_RETENTION_MODULE_SDM0);
|
||||
|
||||
// ESP32H4 supports ASRC sleep retention
|
||||
RETENTION_MODULE_BITMAP_SET(&mask, SLEEP_RETENTION_MODULE_ASRC);
|
||||
|
||||
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);
|
||||
bool ic = sleep_retention_module_bitmap_eq(peripheral_domain_inited_modules, peripheral_domain_created_modules);
|
||||
|
||||
@@ -102,6 +102,9 @@ bool peripheral_domain_pd_allowed(void)
|
||||
//ESP32S31 supports 2D-DMA sleep retention
|
||||
RETENTION_MODULE_BITMAP_SET(&mask, SLEEP_RETENTION_MODULE_DMA2D);
|
||||
|
||||
// ESP32S31 supports ASRC sleep retention
|
||||
RETENTION_MODULE_BITMAP_SET(&mask, SLEEP_RETENTION_MODULE_ASRC);
|
||||
|
||||
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);
|
||||
const sleep_retention_module_bitmap_t peripheral_domain_retained_modules = sleep_retention_module_bitmap_and(retained_modules, mask);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define DR_REG_MEM_MONITOR_BASE 0x60025000
|
||||
#define DR_REG_PVT_BASE 0x60026000
|
||||
#define DR_REG_PCNT_BASE 0x60027000
|
||||
#define DR_REG_SAMPLE_RATE_CONVERTER_BASE 0x60028000
|
||||
#define DR_REG_ASRC_BASE 0x60028000
|
||||
#define DR_REG_ZERO_DET_BASE 0x60029000
|
||||
#define DR_REG_USB_OTG_FS_CORE0_BASE 0x60040000
|
||||
#define DR_REG_USB_OTG_FS_CORE1_BASE 0x6007F000
|
||||
|
||||
@@ -50,18 +50,19 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MCPWM0 = 26,
|
||||
SLEEP_RETENTION_MODULE_MCPWM1 = 27,
|
||||
SLEEP_RETENTION_MODULE_SDM0 = 28,
|
||||
SLEEP_RETENTION_MODULE_ASRC = 29,
|
||||
|
||||
/* Modem module, which includes BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 29,
|
||||
SLEEP_RETENTION_MODULE_BLE_MAC = 30,
|
||||
SLEEP_RETENTION_MODULE_BT_BB = 31,
|
||||
SLEEP_RETENTION_MODULE_802154_MAC = 32,
|
||||
SLEEP_RETENTION_MODULE_POWER = 33,
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 30,
|
||||
SLEEP_RETENTION_MODULE_BLE_MAC = 31,
|
||||
SLEEP_RETENTION_MODULE_BT_BB = 32,
|
||||
SLEEP_RETENTION_MODULE_802154_MAC = 33,
|
||||
SLEEP_RETENTION_MODULE_POWER = 34,
|
||||
|
||||
SLEEP_RETENTION_MODULE_MAX = SOC_PM_RETENTION_MODULE_NUM - 1
|
||||
} periph_retention_module_t;
|
||||
|
||||
#define is_top_domain_module(m) ((m) <= SLEEP_RETENTION_MODULE_SDM0)
|
||||
#define is_top_domain_module(m) ((m) <= SLEEP_RETENTION_MODULE_ASRC)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 51,
|
||||
SLEEP_RETENTION_MODULE_MODEM_PHY = 52,
|
||||
|
||||
SLEEP_RETENTION_MODULE_ASRC = 53,
|
||||
|
||||
SLEEP_RETENTION_MODULE_MAX = SOC_PM_RETENTION_MODULE_NUM - 1
|
||||
} periph_retention_module_t;
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ extern "C" {
|
||||
#define REGDMA_H264_LINK(_pri) ((0x2A << 8) | _pri)
|
||||
#define REGDMA_PPA_LINK(_pri) ((0x2B << 8) | _pri)
|
||||
#define REGDMA_DMA2D_LINK(_pri) ((0x2C << 8) | _pri)
|
||||
#define REGDMA_ASRC_LINK(_pri) ((0x2D << 8) | _pri)
|
||||
|
||||
#define REGDMA_POWER_LINK(_pri) ((0xFD << 8) | _pri)
|
||||
#define REGDMA_CLOCK_ICG_LINK(_pri) ((0xFE << 8) | _pri)
|
||||
@@ -108,6 +109,7 @@ extern "C" {
|
||||
#define REGDMA_LINK_PRI_H264 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
|
||||
#define REGDMA_LINK_PRI_ASRC REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
|
||||
typedef enum {
|
||||
REGDMA_LINK_PRI_0 = 0,
|
||||
|
||||
Reference in New Issue
Block a user