mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-23 01:10:46 +00:00
feat(uart): support uart module sleep retention on c6/h2/p4
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/lock.h>
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
@@ -32,6 +33,7 @@
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "clk_ctrl_os.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
|
||||
#ifdef CONFIG_UART_ISR_IN_IRAM
|
||||
#define UART_ISR_ATTR IRAM_ATTR
|
||||
@@ -95,10 +97,11 @@ static const char *UART_TAG = "uart";
|
||||
// Check actual UART mode set
|
||||
#define UART_IS_MODE_SET(uart_number, mode) ((p_uart_obj[uart_number]->uart_mode == mode))
|
||||
|
||||
#define UART_CONTEXT_INIT_DEF(uart_num) {\
|
||||
.hal.dev = UART_LL_GET_HW(uart_num),\
|
||||
INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)\
|
||||
.hw_enabled = false,\
|
||||
#define UART_CONTEXT_INIT_DEF(uart_num) { \
|
||||
.port_id = uart_num, \
|
||||
.hal.dev = UART_LL_GET_HW(uart_num), \
|
||||
INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \
|
||||
.hw_enabled = false, \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@@ -155,9 +158,15 @@ typedef struct {
|
||||
} uart_obj_t;
|
||||
|
||||
typedef struct {
|
||||
_lock_t mutex; /*!< Protect uart_module_enable, uart_module_disable, retention, etc. */
|
||||
uart_port_t port_id;
|
||||
uart_hal_context_t hal; /*!< UART hal context*/
|
||||
DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)
|
||||
bool hw_enabled;
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
bool retention_link_inited; /*!< Mark whether the retention link is inited */
|
||||
bool retention_link_created; /*!< Mark whether the retention link is created */
|
||||
#endif
|
||||
} uart_context_t;
|
||||
|
||||
static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0};
|
||||
@@ -181,9 +190,13 @@ static uart_context_t uart_context[UART_NUM_MAX] = {
|
||||
|
||||
static portMUX_TYPE uart_selectlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
static esp_err_t uart_create_sleep_retention_link_cb(void *arg);
|
||||
#endif
|
||||
|
||||
static void uart_module_enable(uart_port_t uart_num)
|
||||
{
|
||||
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
_lock_acquire(&(uart_context[uart_num].mutex));
|
||||
if (uart_context[uart_num].hw_enabled != true) {
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
HP_UART_BUS_CLK_ATOMIC() {
|
||||
@@ -194,6 +207,28 @@ static void uart_module_enable(uart_port_t uart_num)
|
||||
uart_ll_reset_register(uart_num);
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// Initialize sleep retention module for HP UART
|
||||
if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) { // Console uart retention has been taken care in sleep_sys_periph_stdout_console_uart_retention_init
|
||||
assert(!uart_context[uart_num].retention_link_inited);
|
||||
sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num);
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = uart_create_sleep_retention_link_cb,
|
||||
.arg = &uart_context[uart_num],
|
||||
},
|
||||
},
|
||||
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
|
||||
};
|
||||
if (sleep_retention_module_init(module, &init_param) == ESP_OK) {
|
||||
uart_context[uart_num].retention_link_inited = true;
|
||||
} else {
|
||||
ESP_LOGW(UART_TAG, "init sleep retention failed for uart%d, power domain may be turned off during sleep", uart_num);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if (SOC_UART_LP_NUM >= 1)
|
||||
else {
|
||||
@@ -205,14 +240,24 @@ static void uart_module_enable(uart_port_t uart_num)
|
||||
#endif
|
||||
uart_context[uart_num].hw_enabled = true;
|
||||
}
|
||||
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
_lock_release(&(uart_context[uart_num].mutex));
|
||||
}
|
||||
|
||||
static void uart_module_disable(uart_port_t uart_num)
|
||||
{
|
||||
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
_lock_acquire(&(uart_context[uart_num].mutex));
|
||||
if (uart_context[uart_num].hw_enabled != false) {
|
||||
if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) {
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// Uninitialize sleep retention module for HP UART
|
||||
sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num);
|
||||
assert(!uart_context[uart_num].retention_link_created); // HP UART sleep retention should have been freed at this moment
|
||||
if (uart_context[uart_num].retention_link_inited) {
|
||||
sleep_retention_module_deinit(module);
|
||||
uart_context[uart_num].retention_link_inited = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
HP_UART_BUS_CLK_ATOMIC() {
|
||||
uart_ll_enable_bus_clock(uart_num, false);
|
||||
}
|
||||
@@ -226,7 +271,7 @@ static void uart_module_disable(uart_port_t uart_num)
|
||||
#endif
|
||||
uart_context[uart_num].hw_enabled = false;
|
||||
}
|
||||
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
_lock_release(&(uart_context[uart_num].mutex));
|
||||
}
|
||||
|
||||
esp_err_t uart_get_sclk_freq(uart_sclk_t sclk, uint32_t *out_freq_hz)
|
||||
@@ -799,6 +844,31 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
|
||||
|
||||
uart_module_enable(uart_num);
|
||||
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// Create sleep retention link if desired
|
||||
if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) {
|
||||
_lock_acquire(&(uart_context[uart_num].mutex));
|
||||
sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num);
|
||||
if (uart_config->flags.backup_before_sleep && !uart_context[uart_num].retention_link_created) {
|
||||
if (uart_context[uart_num].retention_link_inited) {
|
||||
if (sleep_retention_module_allocate(module) == ESP_OK) {
|
||||
uart_context[uart_num].retention_link_created = true;
|
||||
} else {
|
||||
// Even though the sleep retention module create failed, UART driver should still work, so just warning here
|
||||
ESP_LOGW(UART_TAG, "create retention module failed, power domain can't turn off");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(UART_TAG, "retention module not initialized first, unable to create retention module");
|
||||
}
|
||||
} else if (!uart_config->flags.backup_before_sleep && uart_context[uart_num].retention_link_created) {
|
||||
assert(uart_context[uart_num].retention_link_inited);
|
||||
sleep_retention_module_free(module);
|
||||
uart_context[uart_num].retention_link_created = false;
|
||||
}
|
||||
_lock_release(&(uart_context[uart_num].mutex));
|
||||
}
|
||||
#endif
|
||||
|
||||
soc_module_clk_t uart_sclk_sel = 0; // initialize to an invalid module clock ID
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
uart_sclk_sel = (soc_module_clk_t)((uart_config->source_clk) ? uart_config->source_clk : UART_SCLK_DEFAULT); // if no specifying the clock source (soc_module_clk_t starts from 1), then just use the default clock
|
||||
@@ -1712,6 +1782,20 @@ esp_err_t uart_driver_delete(uart_port_t uart_num)
|
||||
periph_rtc_dig_clk8m_disable();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// Free sleep retention link for HP UART
|
||||
if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) {
|
||||
sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num);
|
||||
_lock_acquire(&(uart_context[uart_num].mutex));
|
||||
if (uart_context[uart_num].retention_link_created) {
|
||||
assert(uart_context[uart_num].retention_link_inited);
|
||||
sleep_retention_module_free(module);
|
||||
uart_context[uart_num].retention_link_created = false;
|
||||
}
|
||||
_lock_release(&(uart_context[uart_num].mutex));
|
||||
}
|
||||
#endif
|
||||
uart_module_disable(uart_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1867,3 +1951,17 @@ void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout)
|
||||
p_uart_obj[uart_num]->rx_always_timeout_flg = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
static esp_err_t uart_create_sleep_retention_link_cb(void *arg)
|
||||
{
|
||||
uart_context_t *group = (uart_context_t *)arg;
|
||||
uart_port_t uart_num = group->port_id;
|
||||
sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num);
|
||||
esp_err_t err = sleep_retention_entries_create(uart_reg_retention_info[uart_num].regdma_entry_array,
|
||||
uart_reg_retention_info[uart_num].array_size,
|
||||
REGDMA_LINK_PRI_UART, module);
|
||||
ESP_RETURN_ON_ERROR(err, UART_TAG, "create retention link failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user