feat(uart): support uart module sleep retention on c6/h2/p4

This commit is contained in:
Song Ruo Jing
2024-05-15 19:07:58 +08:00
parent 13e5b6f335
commit dca7c286d0
66 changed files with 707 additions and 277 deletions

View File

@@ -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