Merge branch 'feature/bringup_esp32c6_light_sleep_pd_top' into 'master'

esp32c6: support light_sleep (Stage 2: support Digital Peripheral power down)

See merge request espressif/esp-idf!22197
This commit is contained in:
Wu Zheng Hui
2023-02-15 16:17:53 +08:00
29 changed files with 3283 additions and 17 deletions

View File

@@ -46,6 +46,35 @@ extern "C" {
#define CHOOSE_MACRO_VA_ARG(MACRO_WITH_ARGS, MACRO_WITH_NO_ARGS, ...) CHOOSE_MACRO_VA_ARG_INN(0, ##__VA_ARGS__, MACRO_WITH_ARGS, MACRO_WITH_NO_ARGS, 0)
#endif
/* Count number of arguments of __VA_ARGS__
* - reference https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s
* - __GET_NTH_ARG__() takes args >= N (64) but only expand to Nth one (64th)
* - __RSEQ_N__() is reverse sequential to N to add padding to have Nth
* position is the same as the number of arguments
* - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
*/
#ifndef __VA_NARG__
# define __VA_NARG__(...) __NARG__(_0, ##__VA_ARGS__, __RSEQ_N__())
# define __NARG__(...) __GET_NTH_ARG__(__VA_ARGS__)
# define __GET_NTH_ARG__( \
_01,_02,_03,_04,_05,_06,_07,_08,_09,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
# define __RSEQ_N__() \
62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#endif
/* test macros */
#define foo_args(...) 1
#define foo_no_args() 2

View File

@@ -34,6 +34,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "sleep_cpu.c")
endif()
if(CONFIG_SOC_PAU_SUPPORTED)
list(APPEND srcs "sleep_retention.c" "sleep_peripheral.c" "sleep_clock.c")
endif()
# [refactor-todo]: requires "driver" for GPIO and RTC (by sleep_gpio and sleep_modes)
list(APPEND priv_requires driver esp_timer)
@@ -73,6 +77,11 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "esp_ds.c")
endif()
if(CONFIG_SOC_PAU_SUPPORTED)
list(APPEND srcs "port/pau_regdma.c"
"port/regdma_link.c")
endif()
if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW)
list(APPEND srcs "sleep_cpu_asm.S")
set_property(TARGET ${COMPONENT_LIB}

View File

@@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "soc/soc.h"
#include "soc/soc_caps.h"
#if SOC_PAU_SUPPORTED
#include "hal/pau_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set the addresses of all REGDMA Links
* @param link_entries all linked lists addresses
*/
void pau_regdma_set_entry_link_addr(pau_regdma_link_addr_t *link_entries);
/**
* @brief Set the address of WiFi MAC REGDMA Link in modem state
* @param link_addr linked lists address
*/
void pau_regdma_set_modem_link_addr(void *link_addr);
/**
* @brief Software trigger regdma to perform modem link backup
*/
void pau_regdma_trigger_modem_link_backup(void);
/**
* @brief Software trigger regdma to perform modem link restore
*/
void pau_regdma_trigger_modem_link_restore(void);
/**
* @brief Set the address of extra REGDMA Link in active state
* @param link_addr linked lists address
*/
void pau_regdma_set_extra_link_addr(void *link_addr);
/**
* @brief Software trigger regdma to perform extra link backup
*/
void pau_regdma_trigger_extra_link_backup(void);
/**
* @brief Software trigger regdma to perform extra link restore
*/
void pau_regdma_trigger_extra_link_restore(void);
#ifdef __cplusplus
}
#endif
#endif //SOC_PAU_SUPPORTED

View File

@@ -0,0 +1,649 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_assert.h"
#include "esp_macros.h"
#include "esp_err.h"
#include "esp_bit_defs.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_PAU_SUPPORTED
#include "hal/pau_types.h"
#define REGDMA_LINK_DBG 0 /* Enable REGDMA link info dump apis*/
#define REGDMA_LINK_ENTRY_NUM (PAU_REGDMA_LINK_NUM) /* Maximum number of REG DMA linked list entries */
#define ENTRY(n) (BIT(n))
#define REGDMA_PCR_LINK(_pri) ((0x01 << 8) | _pri)
#define REGDMA_MODEMSYSCON_LINK(_pri) ((0x02 << 8) | _pri)
#define REGDMA_INTMTX_LINK(_pri) ((0x0d << 8) | _pri)
#define REGDMA_HPSYS_LINK(_pri) ((0x0e << 8) | _pri)
#define REGDMA_TEEAPM_LINK(_pri) ((0x0f << 8) | _pri)
#define REGDMA_UART_LINK(_pri) ((0x10 << 8) | _pri)
#define REGDMA_TIMG_LINK(_pri) ((0x11 << 8) | _pri)
#define REGDMA_IOMUX_LINK(_pri) ((0x12 << 8) | _pri)
#define REGDMA_SPIMEM_LINK(_pri) ((0x13 << 8) | _pri)
#define REGDMA_SYSTIMER_LINK(_pri) ((0x14 << 8) | _pri)
typedef enum {
REGDMA_LINK_PRI_0 = 0,
REGDMA_LINK_PRI_1,
REGDMA_LINK_PRI_2,
REGDMA_LINK_PRI_3,
REGDMA_LINK_PRI_4,
REGDMA_LINK_PRI_5,
REGDMA_LINK_PRI_6,
REGDMA_LINK_PRI_7,
} regdma_link_priority_t;
typedef pau_regdma_link_addr_t regdma_entry_buf_t;
typedef enum regdma_link_mode {
REGDMA_LINK_MODE_CONTINUOUS = 0, /*!< Link used to backup registers with consecutive addresses */
REGDMA_LINK_MODE_ADDR_MAP, /*!< Link used to backup selected registers according to bitmap */
REGDMA_LINK_MODE_WRITE, /*!< Link used to direct write to registers*/
REGDMA_LINK_MODE_WAIT /*!< Link used to wait for register value to meet condition*/
} regdma_link_mode_t;
typedef struct regdma_link_head {
volatile uint32_t length: 10, /* total count of registers that need to be backup or restore, unit: 1 word = 4 bytes */
reserve0: 6,
mode : 4, /* mode of current link */
reserve1: 8,
branch : 1, /* branch link flag */
skip_r : 1, /* skip the current linked node when restore the register */
skip_b : 1, /* skip the current linked node when backup the register */
eof : 1; /* end of link */
} regdma_link_head_t;
/* Continuous type linked list node body type definition */
typedef struct regdma_link_continuous_body {
volatile void *next;
volatile void *backup;
volatile void *restore;
volatile void *mem;
} regdma_link_continuous_body_t;
/* Address Map type linked list node body type definition */
typedef struct regdma_link_addr_map_body {
volatile void *next;
volatile void *backup;
volatile void *restore;
volatile void *mem;
volatile uint32_t map[4];
} regdma_link_addr_map_body_t;
/* Write/Wait type linked list node body type definition */
typedef struct regdma_link_write_wait_body {
volatile void *next;
volatile void *backup;
volatile uint32_t value;
volatile uint32_t mask;
} regdma_link_write_wait_body_t;
/* Branch Continuous type linked list node body type definition */
typedef struct regdma_link_branch_continuous_body {
regdma_entry_buf_t next;
volatile void *backup;
volatile void *restore;
volatile void *mem;
} regdma_link_branch_continuous_body_t;
/* Branch Address Map type linked list node body type definition */
typedef struct regdma_link_branch_addr_map_body {
regdma_entry_buf_t next;
volatile void *backup;
volatile void *restore;
volatile void *mem;
volatile uint32_t map[4];
} regdma_link_branch_addr_map_body_t;
/* Branch Write/Wait type linked list node body type definition */
typedef struct regdma_link_branch_write_wait_body {
regdma_entry_buf_t next;
volatile void *backup;
volatile uint32_t value;
volatile uint32_t mask;
} regdma_link_branch_write_wait_body_t;
ESP_STATIC_ASSERT(REGDMA_LINK_ENTRY_NUM < 16, "regdma link entry number should less 16");
typedef struct regdma_link_stats {
volatile uint32_t ref: REGDMA_LINK_ENTRY_NUM, /* a bitmap, identifies which entry has referenced the current link */
reserve: 16-REGDMA_LINK_ENTRY_NUM,
id: 16; /* REGDMA linked list node unique identifier */
volatile uint32_t module; /* a bitmap used to identify the module to which the current node belongs */
} regdma_link_stats_t;
typedef struct regdma_link_continuous {
regdma_link_stats_t stat;
regdma_link_head_t head;
regdma_link_continuous_body_t body;
volatile uint32_t buff[0];
} regdma_link_continuous_t;
typedef struct regdma_link_addr_map {
regdma_link_stats_t stat;
regdma_link_head_t head;
regdma_link_addr_map_body_t body;
volatile uint32_t buff[0];
} regdma_link_addr_map_t;
typedef struct regdma_link_write_wait {
regdma_link_stats_t stat;
regdma_link_head_t head;
regdma_link_write_wait_body_t body;
} regdma_link_write_wait_t;
typedef struct regdma_link_branch_continuous {
regdma_link_stats_t stat;
regdma_link_head_t head;
regdma_link_branch_continuous_body_t body;
volatile uint32_t buff[0];
} regdma_link_branch_continuous_t;
typedef struct regdma_link_branch_addr_map {
regdma_link_stats_t stat;
regdma_link_head_t head;
regdma_link_branch_addr_map_body_t body;
volatile uint32_t buff[0];
} regdma_link_branch_addr_map_t;
typedef struct regdma_link_branch_write_wait {
regdma_link_stats_t stat;
regdma_link_head_t head;
regdma_link_branch_write_wait_body_t body;
} regdma_link_branch_write_wait_t;
typedef struct regdma_link_config {
regdma_link_head_t head;
union {
regdma_link_continuous_body_t continuous;
regdma_link_addr_map_body_t addr_map;
regdma_link_write_wait_body_t write_wait;
};
int id; /* REGDMA linked list node unique identifier */
} regdma_link_config_t;
#define REGDMA_LINK_HEAD(plink) (((regdma_link_config_t *)plink)->head)
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif
#define REGDMA_LINK_HEAD_INIT(_l, _m, _b, _sr, _sb) \
{ \
.length = (_l), \
.mode = (_m), \
.branch = (_b), \
.skip_r = (_sr), \
.skip_b = (_sb), \
.eof = 0 \
}
#define REGDMA_LINK_CONTINUOUS_INIT(_id, _backup, _restore, _len, _skip_b, _skip_r) \
{ \
.head = REGDMA_LINK_HEAD_INIT( \
_len, \
REGDMA_LINK_MODE_CONTINUOUS,\
0, \
_skip_r, \
_skip_b \
), \
.continuous = { \
.next = NULL, \
.backup = (void *)_backup, \
.restore = (void *)_restore, \
.mem = NULL \
}, \
.id = (_id) \
}
#define REGDMA_LINK_ADDR_MAP_INIT(_id, _backup, _restore, _len, _skip_b, _skip_r, ...) \
{ \
.head = REGDMA_LINK_HEAD_INIT( \
_len, \
REGDMA_LINK_MODE_ADDR_MAP, \
0, \
_skip_r, \
_skip_b \
), \
.addr_map = { \
.next = NULL, \
.backup = (void *)_backup, \
.restore = (void *)_restore, \
.mem = NULL, \
.map = {__VA_ARGS__} \
}, \
.id = (_id) \
}
#define REGDMA_LINK_WRITE_INIT(_id, _backup, _val, _mask, _skip_b, _skip_r) \
{ \
.head = REGDMA_LINK_HEAD_INIT( \
0, \
REGDMA_LINK_MODE_WRITE, \
0, \
_skip_r, \
_skip_b \
), \
.write_wait = { \
.next = NULL, \
.backup = (void *)_backup, \
.value = (_val), \
.mask = (_mask) \
}, \
.id = (_id) \
}
#define REGDMA_LINK_WAIT_INIT(_id, _backup, _val, _mask, _skip_b, _skip_r) \
{ \
.head = REGDMA_LINK_HEAD_INIT( \
0, \
REGDMA_LINK_MODE_WAIT, \
0, \
_skip_r, \
_skip_b \
), \
.write_wait = { \
.next = NULL, \
.backup = (void *)_backup, \
.value = (_val), \
.mask = (_mask) \
}, \
.id = (_id) \
}
/**
* @brief Create a REGDMA continuous type linked list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param buff Retention buffer, it needs to be allocated by the caller and passed in by this argument
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_continuous(void *backup, void *buff, int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA addr_map type linked list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param buff Retention buffer, it needs to be allocated by the caller and passed in by this argument
* @param bitmap The register bitmap that needs to be backed up and restored. when the bitmap corresponding to the
* register is 1, it needs to be backed up or restored, otherwise the corresponding register is skipped.
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_addr_map(void *backup, void *buff, uint32_t bitmap[4], int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA write type linked list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param value The value to be written to the register
* @param mask The mask of value
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_write(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA write type linked list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param value The register value that needs to be waited for
* @param mask The mask of value
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_wait(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA continuouos branch list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param buff Retention buffer, it needs to be allocated by the caller and passed in by this argument
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_continuous(void *backup, void *buff, int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA addr_map branch list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param buff Retention buffer, it needs to be allocated by the caller and passed in by this argument
* @param bitmap The register bitmap that needs to be backed up and restored. when the bitmap corresponding to the
* register is 1, it needs to be backed up or restored, otherwise the corresponding register is skipped.
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_addr_map(void *backup, void *buff, uint32_t bitmap[4], int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA write branch list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param value The value to be written to the register
* @param mask The mask of value
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_write(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a REGDMA wait branch list node without retention buffer and the retention buffer is passed in by the caller
* @param backup Register address to be backed up by REGDMA
* @param value The register value that needs to be waited for
* @param mask The mask of value
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_wait(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA continuous type linked list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_continuous_default(void *backup, int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA addr_map type linked list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param bitmap The register bitmap that needs to be backed up and restored. when the bitmap corresponding to the
* register is 1, it needs to be backed up or restored, otherwise the corresponding register is skipped.
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_addr_map_default(void *backup, uint32_t bitmap[4], int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA write type linked list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param value The register value that needs to be waited for
* @param mask The mask of value
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_write_default(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA wait type linked list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param value The register value that needs to be waited for
* @param mask The mask of value
* @param next The next REGDMA linked list node
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_wait_default(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA continuous branch list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_continuous_default(void *backup, int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA addr_map branch list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param bitmap The register bitmap that needs to be backed up and restored. when the bitmap corresponding to the
* register is 1, it needs to be backed up or restored, otherwise the corresponding register is skipped.
* @param len Number of registers to be backed up
* @param restore Register address to be restored by REGDMA
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_addr_map_default(void *backup, uint32_t bitmap[4], int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA write branch list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param value The value to be written to the register
* @param mask The mask of value
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_write_default(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create a default REGDMA wait branch list node with retention buffer
* @param backup Register address to be backed up by REGDMA
* @param value The register value that needs to be waited for
* @param mask The mask of value
* @param next The next REGDMA linked list node (supports up to 4 next pointers)
* @param skip_b Skip backup, True means that REGDMA skips the current node when executing the backup task
* @param skip_r Skip restore, True means that REGDMA skips the current node when executing the restore task
* @param id REGDMA linked list node unique identifier, the caller needs to ensure that the id of each node is unique
* @param module The module identifier of the current linked list node
* @return Created REGDMA linked list node pointer
*/
void *regdma_link_new_branch_wait_default(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module);
/**
* @brief Create and initialize a REGDMA linked list node through configuration parameters
* @param config REGDMA linked node configuration parameters
* @param branch Is it a branch node
* @param module The module identifier of the current linked list node
* @param nentry The number of next pointers
* @param args next pointer, Since REGDMA supports 4 entries, it supports up to 4 variable parameter next pointers, and more will be ignored
* @return Initialized REGDMA linked list head node pointer
*/
void *regdma_link_init(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, ...);
/**
* @brief Recurse the REGDMA linked list and call the hook subroutine for each node
* @param link The REGDMA linkded list head pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param hook Subroutines called during recursion, argument 1 is the pointer to the
* recursive node object, argument 2 is the entry to which the node belongs
* and the argument 3 is the position of the node in the current linked
* list (from head to tail, the position of the head node is 0)
* @return The REGDMA linked list node pointer indicated by the link argument
*/
void *regdma_link_recursive(void *link, int entry, void (*hook)(void *, int, int));
/**
* @brief Find the linked list node object by node position
* @param link The REGDMA linkded list head pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param pos Node position
* @return The linked list node object pointer or NULL
*/
void *regdma_find_link_by_pos(void *link, int entry, int pos);
/**
* @brief Find the linked list node object by node unique identifier
* @param link The REGDMA linkded list head pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param id REGDMA linked list node unique identifier
* @return The linked list node object pointer or NULL
*/
void *regdma_find_link_by_id(void *link, int entry, int id);
/**
* @brief Destroy the REGDMA linked list indicated by the entry argument
* @param link The REGDMA linkded list head pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
*/
void regdma_link_destroy(void *link, int entry);
/**
* @brief Generate the statistics information of the REGDMA linked list indicated by the entry argument
* @param link The REGDMA linkded list head pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
*/
void regdma_link_stats(void *link, int entry);
/**
* @brief Set the value and mask of write or wait type REGDMA linked list node
* @param link Write or wait type REGDMA linked list node pointer
* @param value The value to be written to the register
* @param mask The mask of value
*/
void regdma_link_set_write_wait_content(void *link, uint32_t value, uint32_t mask);
/**
* @brief Print all node information of the REGDMA linked list indicated by the entry argument
* @param link The REGDMA linkded list head pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
*/
void regdma_link_show_memories(void *link, int entry);
/**
* @brief Update REGDMA linked list node next pointers
* @param link The pointer of the REGDMA linked list node whose next field will be modified
* @param nentry The number of next pointers
*/
void regdma_link_update_next(void *link, int nentry, ...);
/**
* @brief Get all node entry reference bitmaps from the start of the link argument to the
* end of the tail argument in the REGDMA linked list indicated by the entry argument
* @param link The REGDMA linkded list head pointer
* @param tail The REGDMA linkded list tail pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @return The entry reference bitmap of all nodes starting from the link argument to the end of the tail argument
*/
uint32_t regdma_link_get_owner_bitmap(void *link, void *tail, int entry);
/**
* @brief Find the head node of the specified module in the REGDMA linked list indicated by the
* entry argument starting from the link argument to the end of the tail argument
* @param link The REGDMA linkded list head pointer
* @param tail The REGDMA linkded list tail pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param module Module bitmap Identification
* @return The found head node pointer or NULL
*/
void *regdma_find_module_link_head(void *link, void *tail, int entry, uint32_t module);
/**
* @brief Find the tail node of the specified module in the REGDMA linked list indicated by the
* entry argument starting from the link argument to the end of the tail argument
* @param link The REGDMA linkded list head pointer
* @param tail The REGDMA linkded list tail pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param module Module bitmap Identification
* @return The found tail node pointer or NULL
*/
void *regdma_find_module_link_tail(void *link, void *tail, int entry, uint32_t module);
/**
* @brief Find the tail node of the previous module of the specified module in the REGDMA linked list
* indicated by the entry argument starting from the link argment to the end of the tail argument
* @param link The REGDMA linkded list head pointer
* @param tail The REGDMA linkded list tail pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param module Module bitmap Identification
* @return The found tail node pointer or NULL
*/
void *regdma_find_prev_module_link_tail(void *link, void *tail, int entry, uint32_t module);
/**
* @brief Find the head node of the next module of the specified module in the REGDMA linked list
* indicated by the entry argument starting from the link argment to the end of the tail argument
* @param link The REGDMA linkded list head pointer
* @param tail The REGDMA linkded list tail pointer
* @param entry For nodes that support branching, use the branch specified by entry argument recursively
* @param module Module bitmap Identification
* @return The found head node pointer or NULL
*/
void *regdma_find_next_module_link_head(void *link, void *tail, int entry, uint32_t module);
#define regdma_link_init_safe(pcfg, branch, module, ...) regdma_link_init((pcfg), (branch), (module), __VA_NARG__(__VA_ARGS__), ##__VA_ARGS__)
#define regdma_link_update_next_safe(link, ...) regdma_link_update_next((link), __VA_NARG__(__VA_ARGS__), ##__VA_ARGS__)
#endif // SOC_PAU_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,199 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __REGDMA_LINK_H__
#define __REGDMA_LINK_H__
#include <stdint.h>
#include <stddef.h>
#include "esp_bit_defs.h"
#include "soc/soc_caps.h"
#if SOC_PAU_SUPPORTED
#include "esp_regdma.h"
#define FILL_PLINK_HEAD(_pl, _len, _mode, _branch, _sr, _sb, _eof) { \
_pl->head.length = _len; \
_pl->head.mode = _mode; \
_pl->head.branch = _branch; \
_pl->head.skip_r = _sr; \
_pl->head.skip_b = _sb; \
_pl->head.eof = _eof; \
}
#define FILL_PLINK_STAT(_pl, _ref, _id, _module) { \
_pl->stat.ref = _ref; \
_pl->stat.id = _id; \
_pl->stat.module = _module; \
}
static inline void * regdma_link_init_continuous(
regdma_link_continuous_t *plink, void *buff, void *backup, int len,
void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
assert(plink != NULL);
assert(buff !=NULL);
FILL_PLINK_HEAD(plink, len, REGDMA_LINK_MODE_CONTINUOUS, 0, skip_r, skip_b, !next);
plink->body.next = next;
plink->body.backup = backup;
plink->body.restore = restore;
plink->body.mem = buff;
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline int regdma_link_addr_map_count(uint32_t bitmap[4])
{
return __builtin_popcount(bitmap[0]) + \
__builtin_popcount(bitmap[1]) + \
__builtin_popcount(bitmap[2]) + \
__builtin_popcount(bitmap[3]);
}
static inline void * regdma_link_init_addr_map(
regdma_link_addr_map_t *plink, void *buff, void *backup, uint32_t bitmap[4],
int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
assert(plink != NULL);
assert(buff != NULL);
assert(len == regdma_link_addr_map_count(bitmap));
FILL_PLINK_HEAD(plink, len, REGDMA_LINK_MODE_ADDR_MAP, 0, skip_r, skip_b, !next);
plink->body.next = next;
plink->body.backup = backup;
plink->body.restore = restore;
plink->body.mem = buff;
plink->body.map[0] = bitmap[0];
plink->body.map[1] = bitmap[1];
plink->body.map[2] = bitmap[2];
plink->body.map[3] = bitmap[3];
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void * regdma_link_init_write(
regdma_link_write_wait_t *plink, void *backup, uint32_t value,
uint32_t mask, void *next, bool skip_b, bool skip_r, int id,
uint32_t module)
{
assert(plink != NULL);
FILL_PLINK_HEAD(plink, 0, REGDMA_LINK_MODE_WRITE, 0, skip_r, skip_b, !next);
plink->body.next = next;
plink->body.backup = backup;
plink->body.value = value;
plink->body.mask = mask;
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void * regdma_link_init_wait(
regdma_link_write_wait_t *plink, void *backup, uint32_t value,
uint32_t mask, void *next, bool skip_b, bool skip_r, int id,
uint32_t module)
{
assert(plink != NULL);
FILL_PLINK_HEAD(plink, 0, REGDMA_LINK_MODE_WAIT, 0, skip_r, skip_b, !next);
plink->body.next = next;
plink->body.backup = backup;
plink->body.value = value;
plink->body.mask = mask;
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void * regdma_link_init_branch_continuous(
regdma_link_branch_continuous_t *plink, void *buff, void *backup, int len, void *restore,
regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
assert(plink != NULL);
assert(buff !=NULL);
FILL_PLINK_HEAD(plink, len, REGDMA_LINK_MODE_CONTINUOUS, 1, skip_r, skip_b, 0);
plink->body.backup = backup;
plink->body.restore = restore;
plink->body.mem = buff;
for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
plink->body.next[i] = (*next)[i];
}
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void * regdma_link_init_branch_addr_map(
regdma_link_branch_addr_map_t *plink, void *buff, void *backup, uint32_t bitmap[4],
int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id,
uint32_t module)
{
assert(plink != NULL);
assert(buff != NULL);
FILL_PLINK_HEAD(plink, len, REGDMA_LINK_MODE_ADDR_MAP, 1, skip_r, skip_b, 0);
plink->body.backup = backup;
plink->body.restore = restore;
plink->body.mem = buff;
memcpy(plink->body.next, *next, REGDMA_LINK_ENTRY_NUM * sizeof((*next)[0]));
plink->body.map[0] = bitmap[0];
plink->body.map[1] = bitmap[1];
plink->body.map[2] = bitmap[2];
plink->body.map[3] = bitmap[3];
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void * regdma_link_init_branch_write(
regdma_link_branch_write_wait_t *plink, void *backup, uint32_t value, uint32_t mask,
regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
assert(plink != NULL);
FILL_PLINK_HEAD(plink, 0, REGDMA_LINK_MODE_WRITE, 1, skip_r, skip_b, 0);
plink->body.backup = backup;
plink->body.value = value;
plink->body.mask = mask;
for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
plink->body.next[i] = (*next)[i];
}
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void * regdma_link_init_branch_wait(
regdma_link_branch_write_wait_t *plink, void *backup, uint32_t value, uint32_t mask,
regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
assert(plink != NULL);
FILL_PLINK_HEAD(plink, 0, REGDMA_LINK_MODE_WAIT, 1, skip_r, skip_b, 0);
plink->body.backup = backup;
plink->body.value = value;
plink->body.mask = mask;
for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
plink->body.next[i] = (*next)[i];
}
FILL_PLINK_STAT(plink, 0, (uint16_t)id, module);
return (void *)plink;
}
static inline void regdma_link_update_stats(regdma_link_stats_t *stats, int entry, int depth)
{
assert(stats != NULL);
stats->ref |= BIT(entry);
}
#endif // SOC_PAU_SUPPORTED
#endif /* __REGDMA_LINK_H__ */

View File

@@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sleep_clock.h
*
* This file contains declarations of digital peripheral clock retention related functions in light sleep mode.
*/
/**
* @brief Whether to allow the TOP power domain to be powered off.
*
* In light sleep mode, only when the system can provide enough memory
* for digital peripheral clock retention, the TOP power domain can be
* powered off.
*
* @return True to allow power off
*/
bool clock_domain_pd_allowed(void);
/**
* @brief PCR module power down initialize
*
* @return ESP_OK on success
* ESP_ERR_INVALID_ARG on invalid sleep_retention_entries_create args
* No memory for the retention link
*/
esp_err_t sleep_clock_system_retention_init(void);
/**
* @brief PCR module power down deinitialize
*/
void sleep_clock_system_retention_deinit(void);
/**
* @brief Modem syscon module power down initialize
*
* @return ESP_OK on success
* ESP_ERR_INVALID_ARG on invalid sleep_retention_entries_create args
* No memory for the retention link
*/
esp_err_t sleep_clock_modem_retention_init(void);
/**
* @brief Modem syscon module power down deinitialize
*/
void sleep_clock_modem_retention_deinit(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sleep_peripheral.h
*
* This file contains declarations of digital peripheral retention related functions in light sleep mode.
*/
/**
* @brief Whether to allow the TOP power domain to be powered off.
*
* In light sleep mode, only when the system can provide enough memory
* for digital peripheral retention, the TOP power domain can be powered off.
*
* @return True to allow power off
*/
bool peripheral_domain_pd_allowed(void);
/**
* @brief Digital peripheral power down initialize\
*
* @return ESP_OK on success
* ESP_ERR_INVALID_ARG on invalid sleep_retention_entries_create args
* No memory for the retention link
*/
void sleep_peripheral_retention_init(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,120 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_PAU_SUPPORTED
#include "esp_regdma.h"
/**
* @file sleep_retention.h
*
* This file contains declarations of sleep retention related functions, it
* includes sleep retention list creation, destruction and debugging interfaces.
*/
typedef enum sleep_retention_module_bitmap {
/* clock module, which includes system and modem */
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = BIT(1),
SLEEP_RETENTION_MODULE_CLOCK_MODEM = BIT(2),
/* modem module, which includes WiFi, BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_WIFI_MAC = BIT(10),
SLEEP_RETENTION_MODULE_WIFI_BB = BIT(11),
SLEEP_RETENTION_MODULE_BLE_MAC = BIT(12),
SLEEP_RETENTION_MODULE_BLE_BB = BIT(13),
SLEEP_RETENTION_MODULE_802154_MAC = BIT(14),
SLEEP_RETENTION_MODULE_802154_BB = BIT(15),
/* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
* TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */
SLEEP_RETENTION_MODULE_INTR_MATRIX = BIT(16),
SLEEP_RETENTION_MODULE_HP_SYSTEM = BIT(17),
SLEEP_RETENTION_MODULE_TEE_APM = BIT(18),
SLEEP_RETENTION_MODULE_UART0 = BIT(19),
SLEEP_RETENTION_MODULE_TG0 = BIT(20),
SLEEP_RETENTION_MODULE_IOMUX = BIT(21),
SLEEP_RETENTION_MODULE_SPIMEM = BIT(22),
SLEEP_RETENTION_MODULE_SYSTIMER = BIT(23),
SLEEP_RETENTION_MODULE_ALL = (uint32_t)-1
} sleep_retention_module_bitmap_t;
typedef regdma_entry_buf_t sleep_retention_entries_t;
typedef struct {
regdma_link_config_t config;
uint32_t owner; /**< Indicates which regdma entries the current node will insert into */
} sleep_retention_entries_config_t;
/**
* @brief Create a runtime sleep retention linked list
*
* @param retent sleep retention linked list node configuration table
* @param num the total number of sleep retention linked list configuration
* items
* @param priority the priority of the created sleep retention linked list
* @param module the bitmap of the module to which the created sleep retention
* linked list belongs
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough memory for sleep retention
* - ESP_ERR_INVALID_ARG if either of the arguments is out of range
*/
esp_err_t sleep_retention_entries_create(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, int module);
/**
* @brief Destroy a runtime sleep retention linked list
*
* @param module the bitmap of the module to be destroyed
*/
void sleep_retention_entries_destroy(int module);
/**
* @brief Print all runtime sleep retention linked lists
*/
void sleep_retention_entries_show_memories(void);
/**
* @brief Find the linked list node with the unique id
*
* @param id the unique identifier of specified linked list node
*
* @return NULL or the address of the linked list node found
*/
void * sleep_retention_find_link_by_id(int id);
/**
* @brief Get the head pointer of all entry linked list of REGDMA
*
* @param entries buffer for getting results
*/
void sleep_retention_entries_get(sleep_retention_entries_t *entries);
/**
* @brief Get all registered modules that require sleep retention
*
* This is an unprotected interface for getting a bitmap of all modules that
* require sleep retention.
*
* It can only be called by the sleep procedure.
*
* @return the bitmap of all modules requiring sleep retention
*/
uint32_t sleep_retention_get_modules(void);
#endif // SOC_PAU_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@@ -61,6 +61,9 @@ typedef enum {
#endif
#if SOC_PM_SUPPORT_VDDSDIO_PD
ESP_PD_DOMAIN_VDDSDIO, //!< VDD_SDIO
#endif
#if SOC_PM_SUPPORT_TOP_PD
ESP_PD_DOMAIN_TOP, //!< SoC TOP
#endif
ESP_PD_DOMAIN_MAX //!< Number of domains
} esp_sleep_pd_domain_t;
@@ -95,6 +98,14 @@ typedef enum {
ESP_SLEEP_WAKEUP_BT, //!< Wakeup caused by BT (light sleep only)
} esp_sleep_source_t;
/**
* @brief Sleep mode
*/
typedef enum {
ESP_SLEEP_MODE_LIGHT_SLEEP, //!< light sleep mode
ESP_SLEEP_MODE_DEEP_SLEEP //!< deep sleep mode
} esp_sleep_mode_t;
/* Leave this type define for compatibility */
typedef esp_sleep_source_t esp_sleep_wakeup_cause_t;

View File

@@ -148,6 +148,9 @@ const pmu_sleep_config_t* pmu_sleep_config_default(
pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags);
config->analog = analog_default;
} else {
pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags);
config->digital = digital_default;
pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags);
if (!(pd_flags & PMU_SLEEP_PD_MODEM)){
analog_default.hp_sys.analog.slp_logic_dbias += 2;
@@ -179,6 +182,11 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi
}
}
static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig)
{
pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
}
static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp)
{
assert(ctx->hal);
@@ -230,6 +238,9 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp)
{
assert(PMU_instance());
pmu_sleep_power_init(PMU_instance(), &config->power, dslp);
if(!dslp){
pmu_sleep_digital_init(PMU_instance(), &config->digital);
}
pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp);
pmu_sleep_param_init(PMU_instance(), &config->param, dslp);
}

View File

@@ -150,6 +150,16 @@ typedef struct {
} \
}
typedef struct {
pmu_hp_sys_cntl_reg_t syscntl;
} pmu_sleep_digital_config_t;
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((pd_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
} \
}
typedef struct {
struct {
pmu_hp_analog_t analog;
@@ -266,9 +276,10 @@ typedef struct {
}
typedef struct {
pmu_sleep_power_config_t power;
pmu_sleep_analog_config_t analog;
pmu_sleep_param_config_t param;
pmu_sleep_power_config_t power;
pmu_sleep_digital_config_t digital;
pmu_sleep_analog_config_t analog;
pmu_sleep_param_config_t param;
} pmu_sleep_config_t;
typedef struct pmu_sleep_machine_constant {

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/soc.h"
#include "soc/pcr_reg.h"
#include "esp_private/esp_pau.h"
#include "esp_private/periph_ctrl.h"
static __attribute__((unused)) const char *TAG = "pau_regdma";
typedef struct {
pau_hal_context_t *hal;
} pau_context_t;
pau_context_t * __attribute__((weak)) PAU_instance(void)
{
static pau_hal_context_t pau_hal = { .dev = NULL };
static pau_context_t pau_context = { .hal = &pau_hal };
if (pau_hal.dev == NULL) {
pau_hal.dev = &PAU;
periph_module_enable(PERIPH_REGDMA_MODULE);
}
return &pau_context;
}
void pau_regdma_set_entry_link_addr(pau_regdma_link_addr_t *link_entries)
{
ESP_LOGD(TAG, "All link addresses %p,%p,%p,%p", (*link_entries)[0], (*link_entries)[1], (*link_entries)[2], (*link_entries)[3]);
pau_hal_set_regdma_entry_link_addr(PAU_instance()->hal, link_entries);
}
void pau_regdma_set_modem_link_addr(void *link_addr)
{
pau_hal_set_regdma_modem_link_addr(PAU_instance()->hal, link_addr);
}
void pau_regdma_trigger_modem_link_backup(void)
{
pau_hal_start_regdma_modem_link(PAU_instance()->hal, true);
pau_hal_stop_regdma_modem_link(PAU_instance()->hal);
}
void pau_regdma_trigger_modem_link_restore(void)
{
pau_hal_start_regdma_modem_link(PAU_instance()->hal, false);
pau_hal_stop_regdma_modem_link(PAU_instance()->hal);
}
void pau_regdma_set_extra_link_addr(void *link_addr)
{
pau_hal_set_regdma_extra_link_addr(PAU_instance()->hal, link_addr);
}
void pau_regdma_trigger_extra_link_backup(void)
{
pau_hal_start_regdma_extra_link(PAU_instance()->hal, true);
pau_hal_stop_regdma_extra_link(PAU_instance()->hal);
}
void pau_regdma_trigger_extra_link_restore(void)
{
pau_hal_start_regdma_extra_link(PAU_instance()->hal, false);
pau_hal_stop_regdma_extra_link(PAU_instance()->hal);
}

View File

@@ -0,0 +1,798 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <sys/cdefs.h>
#include "esp_private/regdma_link.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_regdma.h"
#define REGDMA_LINK_ADDR_ALIGN (4)
#define REGDMA_LINK_MEM_TYPE_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_DEFAULT)
void * regdma_link_new_continuous(void *backup, void *buff, int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_continuous_t *link = (regdma_link_continuous_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN,
buff ? sizeof(regdma_link_continuous_t) : (sizeof(regdma_link_continuous_t) + (len<<2)),
REGDMA_LINK_MEM_TYPE_CAPS
);
if (link) {
memset(link, 0, buff ? sizeof(regdma_link_continuous_t) : (sizeof(regdma_link_continuous_t) + (len<<2)));
void *buf = buff ? buff : (void *)(link->buff);
link = regdma_link_init_continuous(link, buf, backup, len, restore, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_continuous_t, head));
}
return NULL;
}
void * regdma_link_new_addr_map(void *backup, void *buff, uint32_t bitmap[4], int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_addr_map_t *link = (regdma_link_addr_map_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN,
buff ? sizeof(regdma_link_addr_map_t) : (sizeof(regdma_link_addr_map_t) + (len<<2)),
REGDMA_LINK_MEM_TYPE_CAPS
);
if (link) {
memset(link, 0, buff ? sizeof(regdma_link_addr_map_t) : (sizeof(regdma_link_addr_map_t) + (len<<2)));
void *buf = buff ? buff : (void *)(link->buff);
link = regdma_link_init_addr_map(link, buf, backup, bitmap, len, restore, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_addr_map_t, head));
}
return NULL;
}
void * regdma_link_new_write(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_write_wait_t *link = (regdma_link_write_wait_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
if (link) {
memset(link, 0, sizeof(regdma_link_write_wait_t));
link = regdma_link_init_write(link, backup, value, mask, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_write_wait_t, head));
}
return NULL;
}
void * regdma_link_new_wait(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_write_wait_t *link = (regdma_link_write_wait_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
if (link) {
memset(link, 0, sizeof(regdma_link_write_wait_t));
link = regdma_link_init_wait(link, backup, value, mask, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_write_wait_t, head));
}
return NULL;
}
void * regdma_link_new_branch_continuous(void *backup, void *buff, int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_branch_continuous_t *link = (regdma_link_branch_continuous_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN,
buff ? sizeof(regdma_link_branch_continuous_t) : (sizeof(regdma_link_branch_continuous_t) + (len<<2)),
REGDMA_LINK_MEM_TYPE_CAPS
);
if (link) {
memset(link, 0, buff ? sizeof(regdma_link_branch_continuous_t) : (sizeof(regdma_link_branch_continuous_t) + (len<<2)));
void *buf = buff ? buff : (void *)(link->buff);
link = regdma_link_init_branch_continuous(link, buf, backup, len, restore, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_branch_continuous_t, head));
}
return NULL;
}
void * regdma_link_new_branch_addr_map(void *backup, void *buff, uint32_t bitmap[4], int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_branch_addr_map_t *link = (regdma_link_branch_addr_map_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN,
buff ? sizeof(regdma_link_branch_addr_map_t) : (sizeof(regdma_link_branch_addr_map_t) + (len<<2)),
REGDMA_LINK_MEM_TYPE_CAPS
);
if (link) {
memset(link, 0, buff ? sizeof(regdma_link_branch_addr_map_t) : (sizeof(regdma_link_branch_addr_map_t) + (len<<2)));
void *buf = buff ? buff : (void *)(link->buff);
link = regdma_link_init_branch_addr_map(link, buf, backup, bitmap, len, restore, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_branch_addr_map_t, head));
}
return NULL;
}
void * regdma_link_new_branch_write(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_branch_write_wait_t *link = (regdma_link_branch_write_wait_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_branch_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
if (link) {
memset(link, 0, sizeof(regdma_link_branch_write_wait_t));
link = regdma_link_init_branch_write(link, backup, value, mask, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_branch_write_wait_t, head));
}
return NULL;
}
void * regdma_link_new_branch_wait(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
regdma_link_branch_write_wait_t *link = (regdma_link_branch_write_wait_t *)heap_caps_aligned_alloc(
REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_branch_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
if (link) {
memset(link, 0, sizeof(regdma_link_branch_write_wait_t));
link = regdma_link_init_branch_wait(link, backup, value, mask, next, skip_b, skip_r, id, module);
return (void *)((void *)link + offsetof(regdma_link_branch_write_wait_t, head));
}
return NULL;
}
void * regdma_link_new_continuous_default(void *backup, int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_continuous(backup, NULL, len, restore, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_addr_map_default(void *backup, uint32_t bitmap[4], int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_addr_map(backup, NULL, bitmap, len, restore, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_write_default(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_write(backup, value, mask, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_wait_default(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_wait(backup, value, mask, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_branch_continuous_default(void *backup, int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_branch_continuous(backup, NULL, len, restore, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_branch_addr_map_default(void *backup, uint32_t bitmap[4], int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_branch_addr_map(backup, NULL, bitmap, len, restore, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_branch_write_default(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_branch_write(backup, value, mask, next, skip_b, skip_r, id, module);
}
void * regdma_link_new_branch_wait_default(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
{
return regdma_link_new_branch_wait(backup, value, mask, next, skip_b, skip_r, id, module);
}
static void * regdma_link_init_continuous_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_continuous_default((void *)(config->continuous.backup), config->head.length,
(void *)(config->continuous.restore), next[0], config->head.skip_b,
config->head.skip_r, config->id, module);
}
static void * regdma_link_init_addr_map_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_addr_map_default((void *)(config->addr_map.backup), (void *)(config->addr_map.map),
config->head.length, (void *)(config->addr_map.restore), next[0], config->head.skip_b,
config->head.skip_r, config->id, module);
}
static void * regdma_link_init_write_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_write_default((void *)(config->write_wait.backup), config->write_wait.value,
config->write_wait.mask, next[0], config->head.skip_b, config->head.skip_r,
config->id, module);
}
static void * regdma_link_init_wait_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_wait_default((void *)(config->write_wait.backup), config->write_wait.value,
config->write_wait.mask, next[0], config->head.skip_b, config->head.skip_r,
config->id, module);
}
static void * regdma_link_init_branch_continuous_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_branch_continuous_default((void *)(config->continuous.backup),
config->head.length, (void *)(config->continuous.restore), &next,
config->head.skip_b, config->head.skip_r, config->id, module);
}
static void * regdma_link_init_branch_addr_map_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_branch_addr_map_default((void *)(config->addr_map.backup),
(void *)(config->addr_map.map), config->head.length, (void *)(config->addr_map.restore),
&next, config->head.skip_b, config->head.skip_r, config->id, module);
}
static void * regdma_link_init_branch_write_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_branch_write_default((void *)(config->write_wait.backup),
config->write_wait.value, config->write_wait.mask, &next, config->head.skip_b,
config->head.skip_r, config->id, module);
}
static void * regdma_link_init_branch_wait_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
{
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
return regdma_link_new_branch_wait_default((void *)(config->write_wait.backup),
config->write_wait.value, config->write_wait.mask, &next, config->head.skip_b,
config->head.skip_r, config->id, module);
}
static void * regdma_link_init_wrapper(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, va_list args)
{
typedef void * (*init_fn_t)(const void *, uint32_t, int, va_list);
const static init_fn_t initfn[] = {
[0] = (init_fn_t)regdma_link_init_continuous_wrapper, /* REGDMA_LINK_MODE_CONTINUOUS */
[1] = (init_fn_t)regdma_link_init_addr_map_wrapper, /* REGDMA_LINK_MODE_ADDR_MAP */
[2] = (init_fn_t)regdma_link_init_write_wrapper, /* REGDMA_LINK_MODE_WRITE */
[3] = (init_fn_t)regdma_link_init_wait_wrapper /* REGDMA_LINK_MODE_WAIT */
};
const static init_fn_t initfn_b[] = {
[0] = (init_fn_t)regdma_link_init_branch_continuous_wrapper,
[1] = (init_fn_t)regdma_link_init_branch_addr_map_wrapper,
[2] = (init_fn_t)regdma_link_init_branch_write_wrapper,
[3] = (init_fn_t)regdma_link_init_branch_wait_wrapper
};
assert((config->head.mode < ARRAY_SIZE(initfn)) && (config->head.mode < ARRAY_SIZE(initfn_b)));
init_fn_t pfn = branch ? initfn_b[config->head.mode] : initfn[config->head.mode];
return (*pfn)(config, module, nentry, args);
}
void * regdma_link_init(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, ...)
{
assert(config != NULL);
va_list args;
va_start(args, nentry);
void * link = regdma_link_init_wrapper(config, branch, module, nentry, args);
va_end(args);
return link;
}
static void * regdma_link_get_next_continuous_wrapper(void *link)
{
regdma_link_continuous_t *continuous = __containerof(link, regdma_link_continuous_t, head);
return (void *)(continuous->body.next);
}
static void * regdma_link_get_next_addr_map_wrapper(void *link)
{
regdma_link_addr_map_t *addr_map = __containerof(link, regdma_link_addr_map_t, head);
return (void *)(addr_map->body.next);
}
static void * regdma_link_get_next_write_wait_wrapper(void *link)
{
regdma_link_write_wait_t *write_wait = __containerof(link, regdma_link_write_wait_t, head);
return (void *)(write_wait->body.next);
}
static regdma_entry_buf_t * regdma_link_get_next_branch_continuous_wrapper(void *link)
{
regdma_link_branch_continuous_t *branch_continuous = __containerof(link, regdma_link_branch_continuous_t, head);
return &branch_continuous->body.next;
}
static regdma_entry_buf_t * regdma_link_get_next_branch_addr_map_wrapper(void *link)
{
regdma_link_branch_addr_map_t *branch_addr_map = __containerof(link, regdma_link_branch_addr_map_t, head);
return &branch_addr_map->body.next;
}
static regdma_entry_buf_t * regdma_link_get_next_branch_write_wait_wrapper(void *link)
{
regdma_link_branch_write_wait_t *branch_write_wait = __containerof(link, regdma_link_branch_write_wait_t, head);
return &branch_write_wait->body.next;
}
static void * regdma_link_get_next(void *link, int entry)
{
if (link) {
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
if (head.branch) {
typedef regdma_entry_buf_t * (*get_nextfn1_t)(void *);
const static get_nextfn1_t nextfn1[] = {
[0] = (get_nextfn1_t)regdma_link_get_next_branch_continuous_wrapper,
[1] = (get_nextfn1_t)regdma_link_get_next_branch_addr_map_wrapper,
[2] = (get_nextfn1_t)regdma_link_get_next_branch_write_wait_wrapper,
[3] = (get_nextfn1_t)regdma_link_get_next_branch_write_wait_wrapper
};
assert(head.mode < ARRAY_SIZE(nextfn1));
regdma_entry_buf_t *next = (*nextfn1[head.mode])(link);
if ((entry < REGDMA_LINK_ENTRY_NUM) && (*next)[entry] && (head.eof == 0)) {
return (*next)[entry];
}
} else {
typedef void * (*get_nextfn0_t)(void *);
const static get_nextfn0_t nextfn0[] = {
[0] = (get_nextfn0_t)regdma_link_get_next_continuous_wrapper,
[1] = (get_nextfn0_t)regdma_link_get_next_addr_map_wrapper,
[2] = (get_nextfn0_t)regdma_link_get_next_write_wait_wrapper,
[3] = (get_nextfn0_t)regdma_link_get_next_write_wait_wrapper
};
assert(head.mode < ARRAY_SIZE(nextfn0));
void *next = (*nextfn0[head.mode])(link);
if (next && (head.eof == 0)) {
return next;
}
}
}
return NULL;
}
static void * regdma_link_recursive_impl(void *link, int entry, int depth, void (*hook)(void *, int, int))
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
if (link) {
regdma_link_recursive_impl(regdma_link_get_next(link, entry), entry, depth+1, hook);
if (hook) {
(*hook)(link, entry, depth);
}
}
return link;
}
void * regdma_link_recursive(void *link, int entry, void (*hook)(void *, int, int))
{
return regdma_link_recursive_impl(link, entry, 0, hook);
}
static void * regdma_link_get_instance(void *link)
{
void * container_memaddr[] = {
(void *)__containerof(link, regdma_link_continuous_t, head),
(void *)__containerof(link, regdma_link_addr_map_t, head),
(void *)__containerof(link, regdma_link_write_wait_t, head),
(void *)__containerof(link, regdma_link_write_wait_t, head),
(void *)__containerof(link, regdma_link_branch_continuous_t, head),
(void *)__containerof(link, regdma_link_branch_addr_map_t, head),
(void *)__containerof(link, regdma_link_branch_write_wait_t, head),
(void *)__containerof(link, regdma_link_branch_write_wait_t, head)
};
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
int it = (head.branch << 2) | head.mode;
assert(it < ARRAY_SIZE(container_memaddr));
return container_memaddr[it];
}
static regdma_link_stats_t * regdma_link_get_stats(void *link)
{
const static size_t stats_offset[] = {
offsetof(regdma_link_continuous_t, stat),
offsetof(regdma_link_addr_map_t, stat),
offsetof(regdma_link_write_wait_t, stat),
offsetof(regdma_link_write_wait_t, stat),
offsetof(regdma_link_branch_continuous_t, stat),
offsetof(regdma_link_branch_addr_map_t, stat),
offsetof(regdma_link_branch_write_wait_t, stat),
offsetof(regdma_link_branch_write_wait_t, stat)
};
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
int it = (head.branch << 2) | head.mode;
assert(it < ARRAY_SIZE(stats_offset));
return (regdma_link_stats_t *)(regdma_link_get_instance(link) + stats_offset[it]);
}
static void regdma_link_update_stats_wrapper(void *link, int entry, int depth)
{
if (link == NULL) {
return;
}
regdma_link_update_stats(regdma_link_get_stats(link), entry, depth);
}
void regdma_link_stats(void *link, int entry)
{
regdma_link_recursive_impl(link, entry, 0, regdma_link_update_stats_wrapper);
}
static void regdma_link_destroy_wrapper(void *link, int entry, int depth)
{
if (link == NULL) {
return;
}
regdma_link_stats_t *stat = regdma_link_get_stats(link);
stat->ref &= ~BIT(entry);
if (stat->ref == 0) {
free(regdma_link_get_instance(link));
}
}
void regdma_link_destroy(void *link, int entry)
{
regdma_link_recursive_impl(link, entry, 0, regdma_link_destroy_wrapper);
}
void * regdma_find_link_by_pos(void *link, int entry, int pos)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *next = link;
if (link) {
int iter = 0;
do {
if (pos == iter++) {
break;
}
} while ((next = regdma_link_get_next(next, entry)) != NULL);
}
return next;
}
void * regdma_find_link_by_id(void *link, int entry, int id)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *find_addr = NULL;
void *next = link;
if (link) {
int linkid = 0;
do {
regdma_link_head_t head = REGDMA_LINK_HEAD(next);
if (head.branch) {
regdma_link_branch_continuous_t *continuous = (regdma_link_branch_continuous_t *)regdma_link_get_instance(next);
linkid = continuous->stat.id;
} else {
regdma_link_continuous_t *continuous = (regdma_link_continuous_t *)regdma_link_get_instance(next);
linkid = continuous->stat.id;
}
if (linkid == id) {
find_addr = next;
break;
}
} while ((next = regdma_link_get_next(next, entry)) != NULL);
}
return find_addr;
}
void regdma_link_set_write_wait_content(void *link, uint32_t value, uint32_t mask)
{
if (link) {
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
if (head.mode == REGDMA_LINK_MODE_WRITE || head.mode == REGDMA_LINK_MODE_WAIT) {
if (head.branch) {
regdma_link_branch_write_wait_t *write_wait = (regdma_link_branch_write_wait_t *)regdma_link_get_instance(link);
write_wait->body.value = value;
write_wait->body.mask = mask;
} else {
regdma_link_write_wait_t *write_wait = (regdma_link_write_wait_t *)regdma_link_get_instance(link);
write_wait->body.value = value;
write_wait->body.mask = mask;
}
}
}
}
static void regdma_link_update_continuous_next_wrapper(void *link, void *next)
{
regdma_link_continuous_t *continuous = __containerof(link, regdma_link_continuous_t, head);
continuous->body.next = next;
}
static void regdma_link_update_addr_map_next_wrapper(void *link, void *next)
{
regdma_link_addr_map_t *addr_map = __containerof(link, regdma_link_addr_map_t, head);
addr_map->body.next = next;
}
static void regdma_link_update_write_wait_next_wrapper(void *link, void *next)
{
regdma_link_write_wait_t *write_wait = __containerof(link, regdma_link_write_wait_t, head);
write_wait->body.next = next;
}
static void regdma_link_update_branch_continuous_next_wrapper(void *link, regdma_entry_buf_t *next)
{
regdma_link_branch_continuous_t *branch_continuous = __containerof(link, regdma_link_branch_continuous_t, head);
for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
branch_continuous->body.next[i] = (*next)[i];
}
}
static void regdma_link_update_branch_addr_map_next_wrapper(void *link, regdma_entry_buf_t *next)
{
regdma_link_branch_addr_map_t *branch_addr_map = __containerof(link, regdma_link_branch_addr_map_t, head);
for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
branch_addr_map->body.next[i] = (*next)[i];
}
}
static void regdma_link_update_branch_write_wait_next_wrapper(void *link, regdma_entry_buf_t *next)
{
regdma_link_branch_write_wait_t *branch_write_wait = __containerof(link, regdma_link_branch_write_wait_t, head);
for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
branch_write_wait->body.next[i] = (*next)[i];
}
}
void regdma_link_update_next(void *link, int nentry, ...)
{
va_list args;
va_start(args, nentry);
if (link) {
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < nentry && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
if (head.branch) {
typedef void (*update_branch_fn_t)(void *, regdma_entry_buf_t *);
static const update_branch_fn_t updatefn_b[] = {
[0] = regdma_link_update_branch_continuous_next_wrapper,
[1] = regdma_link_update_branch_addr_map_next_wrapper,
[2] = regdma_link_update_branch_write_wait_next_wrapper,
[3] = regdma_link_update_branch_write_wait_next_wrapper
};
assert((head.mode < ARRAY_SIZE(updatefn_b)));
(*updatefn_b[head.mode])(link, &next);
} else {
typedef void (*update_fn_t)(void *, void *);
static const update_fn_t updatefn[] = {
[0] = regdma_link_update_continuous_next_wrapper,
[1] = regdma_link_update_addr_map_next_wrapper,
[2] = regdma_link_update_write_wait_next_wrapper,
[3] = regdma_link_update_write_wait_next_wrapper
};
assert((head.mode < ARRAY_SIZE(updatefn)));
(*updatefn[head.mode])(link, next[0]);
}
}
va_end(args);
}
uint32_t regdma_link_get_owner_bitmap(void *link, void *tail, int entry)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
uint32_t owner = 0;
void *next = link;
if (link) {
do {
owner |= regdma_link_get_stats(next)->ref;
if (next == tail) {
break;
}
} while ((next = regdma_link_get_next(next, entry)) != NULL);
}
return owner;
}
void * regdma_find_module_link_head(void *link, void *tail, int entry, uint32_t module)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *find_link = NULL;
void *next = link;
if (link) {
do {
if (next == tail) {
break;
}
if (regdma_link_get_stats(next)->module & module) {
find_link = next;
break;
}
} while ((next = regdma_link_get_next(next, entry)) != NULL);
}
return find_link;
}
void * regdma_find_module_link_tail(void *link, void *tail, int entry, uint32_t module)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *find_tail = NULL;
void *next = link;
if (link) {
do {
if (next != tail) {
void *temp = regdma_link_get_next(next, entry);
if ((regdma_link_get_stats(next)->module & module) &&
!(regdma_link_get_stats(temp)->module & module)) {
find_tail = next;
break;
}
} else {
if (regdma_link_get_stats(next)->module & module) {
find_tail = next;
break;
}
}
} while ((next = regdma_link_get_next(next, entry)) != NULL);
}
return find_tail;
}
void * regdma_find_next_module_link_head(void *link, void *tail, int entry, uint32_t module)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *find_tail = regdma_find_module_link_tail(link, tail, entry, module);
if (find_tail && find_tail != tail) {
return regdma_link_get_next(find_tail, entry);
}
return NULL;
}
void * regdma_find_prev_module_link_tail(void *link, void *tail, int entry, uint32_t module)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *find_head = regdma_find_module_link_head(link, tail, entry, module);
void *next = link;
if (find_head && find_head != link) {
do {
if (next == tail) {
break;
}
if (regdma_link_get_next(next, entry) == find_head) {
return next;
}
} while ((next = regdma_link_get_next(next, entry)) != NULL);
}
return NULL;
}
#if REGDMA_LINK_DBG
static const char *TAG = "regdma_link";
static void print_info_continuous_wrapper(void *link)
{
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
regdma_link_continuous_t *cons = __containerof(link, regdma_link_continuous_t, head);
ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:%x, backup:%x, restore:%x, buff:%x",
cons->stat.module, cons->stat.id, link, cons->head, cons->body.next,
cons->body.backup, cons->body.restore, cons->body.mem);
ESP_LOG_BUFFER_HEX(TAG, (const void *)cons->body.mem, head.length);
}
static void print_info_addr_map_wrapper(void *link)
{
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
regdma_link_addr_map_t *map = __containerof(link, regdma_link_addr_map_t, head);
ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:%x, backup:%x, restore:%x, buff:%x, map:{%x,%x,%x,%x}",
map->stat.module, map->stat.id, link, map->head, map->body.next, map->body.backup,
map->body.restore, map->body.mem, map->body.map[0], map->body.map[1],
map->body.map[2], map->body.map[3]);
ESP_LOG_BUFFER_HEX(TAG, (const void *)map->body.mem, head.length);
}
static void print_info_write_wait_wrapper(void *link)
{
regdma_link_write_wait_t *ww = __containerof(link, regdma_link_write_wait_t, head);
ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:%x, backup:%x, value:%x, mask:%x",
ww->stat.module, ww->stat.id, link, ww->head, ww->body.next,
ww->body.backup, ww->body.value, ww->body.mask);
}
static void print_info_branch_continuous_wrapper(void *link)
{
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
regdma_link_branch_continuous_t *cons = __containerof(link, regdma_link_branch_continuous_t, head);
ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:{%x,%x,%x,%x}, backup:%x, restore:%x, buff:%x",
cons->stat.module, cons->stat.id, link, cons->head, cons->body.next[0], cons->body.next[1],
cons->body.next[2], cons->body.next[3], cons->body.backup, cons->body.restore,
cons->body.mem);
ESP_LOG_BUFFER_HEX(TAG, (const void *)cons->body.mem, head.length);
}
static void print_info_branch_addr_map_wrapper(void *link)
{
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
regdma_link_branch_addr_map_t *map = __containerof(link, regdma_link_branch_addr_map_t, head);
ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:{%x,%x,%x,%x}, backup:%x, restore:%x, buff:%x, map:{%x,%x,%x,%x}",
map->stat.module, map->stat.id, link, map->head, map->body.next[0], map->body.next[1], map->body.next[2],
map->body.next[3], map->body.backup, map->body.restore, map->body.mem, map->body.map[0],
map->body.map[1], map->body.map[2], map->body.map[3]);
ESP_LOG_BUFFER_HEX(TAG, (const void *)map->body.mem, head.length);
}
static void print_info_branch_write_wait_wrapper(void *link)
{
regdma_link_branch_write_wait_t *ww = __containerof(link, regdma_link_branch_write_wait_t, head);
ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:{%x,%x,%x,%x}, backup:%x, value:%x, mask:%x",
ww->stat.module, ww->stat.id, link, ww->head, ww->body.next[0], ww->body.next[1],
ww->body.next[2], ww->body.next[3], ww->body.backup, ww->body.value,
ww->body.mask);
}
static void print_link_info(void *args, int entry, int depth)
{
typedef void (*prinf_fn_t)(void *);
const static prinf_fn_t prinf_fn[] = {
[0] = (prinf_fn_t)print_info_continuous_wrapper,
[1] = (prinf_fn_t)print_info_addr_map_wrapper,
[2] = (prinf_fn_t)print_info_write_wait_wrapper,
[3] = (prinf_fn_t)print_info_write_wait_wrapper,
[4] = (prinf_fn_t)print_info_branch_continuous_wrapper,
[5] = (prinf_fn_t)print_info_branch_addr_map_wrapper,
[6] = (prinf_fn_t)print_info_branch_write_wait_wrapper,
[7] = (prinf_fn_t)print_info_branch_write_wait_wrapper
};
regdma_link_head_t head = REGDMA_LINK_HEAD(args);
int it = (head.branch << 2) | head.mode;
assert(it < ARRAY_SIZE(prinf_fn));
(*prinf_fn[it])(args);
}
void regdma_link_show_memories(void *link, int entry)
{
assert(entry < REGDMA_LINK_ENTRY_NUM);
void *next = link;
if (link) {
do {
print_link_info(next, entry, 0);
} while ((next = regdma_link_get_next(next, entry)) != NULL);
} else {
ESP_EARLY_LOGW(TAG, "This REGDMA linked list is empty!\n");
}
}
#endif

View File

@@ -0,0 +1,87 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_check.h"
#include "esp_regdma.h"
#include "esp_private/startup_internal.h"
#include "esp_private/sleep_retention.h"
#include "esp_private/sleep_clock.h"
#include "soc/pcr_reg.h"
#include "modem/modem_syscon_reg.h"
static __attribute__((unused)) const char *TAG = "sleep_clock";
esp_err_t sleep_clock_system_retention_init(void)
{
#define N_REGS_PCR() (((PCR_SRAM_POWER_CONF_REG - DR_REG_PCR_BASE) / 4) + 1)
const static sleep_retention_entries_config_t pcr_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(0), DR_REG_PCR_BASE, DR_REG_PCR_BASE, N_REGS_PCR(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* pcr */
};
esp_err_t err = sleep_retention_entries_create(pcr_regs_retention, ARRAY_SIZE(pcr_regs_retention), REGDMA_LINK_PRI_1, SLEEP_RETENTION_MODULE_CLOCK_SYSTEM);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for system (PCR) retention");
ESP_LOGI(TAG, "System Power, Clock and Reset sleep retention initialization");
return ESP_OK;
}
void sleep_clock_system_retention_deinit(void)
{
sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM);
}
esp_err_t sleep_clock_modem_retention_init(void)
{
#define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1)
const static sleep_retention_entries_config_t modem_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) } /* MODEM SYSCON */
};
esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_2, SLEEP_RETENTION_MODULE_CLOCK_MODEM);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for modem (SYSCON) retention");
ESP_LOGI(TAG, "Modem Power, Clock and Reset sleep retention initialization");
return ESP_OK;
}
void sleep_clock_modem_retention_deinit(void)
{
sleep_retention_entries_destroy(SLEEP_RETENTION_MODULE_CLOCK_MODEM);
}
bool IRAM_ATTR clock_domain_pd_allowed(void)
{
const uint32_t modules = sleep_retention_get_modules();
const uint32_t mask = (const uint32_t) (
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM
#if CONFIG_MAC_BB_PD
| SLEEP_RETENTION_MODULE_CLOCK_MODEM
#endif
);
return ((modules & mask) == mask);
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP || CONFIG_MAC_BB_PD
ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, BIT(0), 106)
{
sleep_clock_system_retention_init();
#if CONFIG_MAC_BB_PD
sleep_clock_modem_retention_init();
#endif
return ESP_OK;
}
#endif

View File

@@ -185,9 +185,13 @@ void esp_deep_sleep_wakeup_io_reset(void)
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO
ESP_SYSTEM_INIT_FN(esp_sleep_startup_init, BIT(0), 105)
{
/* If the TOP domain is powered off, the GPIO will also be powered off during sleep,
and all configurations in the sleep state of GPIO will not take effect.*/
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
// Configure to isolate (disable the Input/Output/Pullup/Pulldown
// function of the pin) all GPIO pins in sleep state
esp_sleep_config_gpio_isolate();
#endif
// Enable automatic switching of GPIO configuration
esp_sleep_enable_gpio_switch(true);
return ESP_OK;

View File

@@ -76,6 +76,8 @@
#include "esp32c6/rom/rtc.h"
#include "hal/lp_timer_hal.h"
#include "esp_private/esp_pmu.h"
#include "esp_private/sleep_peripheral.h"
#include "esp_private/sleep_clock.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/rtc.h"
#include "esp32h2/rom/cache.h"
@@ -392,22 +394,24 @@ inline static void IRAM_ATTR misc_modules_wake_prepare(void)
inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp);
inline static bool is_light_sleep(uint32_t pd_flags)
{
return (pd_flags & RTC_SLEEP_PD_DIG) == 0;
}
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mode)
{
// Stop UART output so that output is not lost due to APB frequency change.
// For light sleep, suspend UART output — it will resume after wakeup.
// For deep sleep, wait for the contents of UART FIFO to be sent.
bool deep_sleep = pd_flags & RTC_SLEEP_PD_DIG;
bool deep_sleep = (mode == ESP_SLEEP_MODE_DEEP_SLEEP);
if (deep_sleep) {
flush_uarts();
} else {
suspend_uarts();
#if SOC_PM_SUPPORT_TOP_PD
if (pd_flags & PMU_SLEEP_PD_TOP) {
flush_uarts();
} else
#endif
{
suspend_uarts();
}
}
#if SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256
@@ -482,7 +486,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
#endif
uint32_t reject_triggers = 0;
if (is_light_sleep(pd_flags)) {
if (!deep_sleep) {
/* Light sleep, enable sleep reject for faster return from this function,
* in case the wakeup is already triggerred.
*/
@@ -542,14 +546,14 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
size_t rtc_fast_length = (size_t)_rtc_force_fast_end - (size_t)_rtc_text_start;
#endif
esp_rom_set_rtc_wake_addr((esp_rom_wake_func_t)esp_wake_stub_entry, rtc_fast_length);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#else
#if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
#if SOC_RTC_FAST_MEM_SUPPORTED
set_rtc_memory_crc();
#endif
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#else
/* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
@@ -560,6 +564,13 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
result = ESP_OK;
#endif
} else {
/* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode.
In order to avoid the leakage of the SPI cs pin, hold it here */
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
rtcio_ll_force_hold_enable(SPI_CS0_GPIO_NUM);
#endif
#if SOC_PM_CPU_RETENTION_BY_SW
if (pd_flags & PMU_SLEEP_PD_CPU) {
result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
@@ -567,7 +578,12 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
}
#else
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#endif
/* Unhold the SPI CS pin */
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
rtcio_ll_force_hold_disable(SPI_CS0_GPIO_NUM);
#endif
}
@@ -641,7 +657,7 @@ void IRAM_ATTR esp_deep_sleep_start(void)
#endif
// Enter sleep
esp_sleep_start(force_pd_flags | pd_flags);
esp_sleep_start(force_pd_flags | pd_flags, ESP_SLEEP_MODE_DEEP_SLEEP);
// Because RTC is in a slower clock domain than the CPU, it
// can take several CPU cycles for the sleep mode to start.
@@ -664,7 +680,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
uint32_t flash_enable_time_us)
{
// Enter sleep
uint32_t reject = esp_sleep_start(pd_flags);
uint32_t reject = esp_sleep_start(pd_flags, ESP_SLEEP_MODE_LIGHT_SLEEP);
#if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
@@ -1455,6 +1471,12 @@ static uint32_t get_power_down_flags(void)
}
#endif
#if SOC_PM_SUPPORT_TOP_PD
if (!cpu_domain_pd_allowed() || !clock_domain_pd_allowed() || !peripheral_domain_pd_allowed()) {
s_config.domain[ESP_PD_DOMAIN_TOP].pd_option = ESP_PD_OPTION_ON;
}
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option = ESP_PD_OPTION_OFF;
#endif
@@ -1512,6 +1534,11 @@ static uint32_t get_power_down_flags(void)
if (s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_XTAL;
}
#if SOC_PM_SUPPORT_TOP_PD
if (s_config.domain[ESP_PD_DOMAIN_TOP].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= PMU_SLEEP_PD_TOP;
}
#endif
#if SOC_PM_SUPPORT_VDDSDIO_PD
if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_VDDSDIO;

View File

@@ -0,0 +1,254 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_private/startup_internal.h"
#include "esp_private/sleep_retention.h"
#include "esp_regdma.h"
#include "soc/uart_reg.h"
#include "soc/systimer_reg.h"
#include "soc/timer_group_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/hp_system_reg.h"
#include "soc/tee_reg.h"
#include "soc/hp_apm_reg.h"
#include "soc/gpio_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/interrupt_matrix_reg.h"
static __attribute__((unused)) const char *TAG = "sleep_peripheral";
#define SLEEP_RETENTION_PERIPHERALS_PRIORITY_DEFAULT (REGDMA_LINK_PRI_6)
esp_err_t sleep_peripheral_intr_matrix_retention_init(void)
{
#define N_REGS_INTR_MATRIX() (((INTMTX_CORE0_CLOCK_GATE_REG - DR_REG_INTERRUPT_MATRIX_BASE) / 4) + 1)
const static sleep_retention_entries_config_t intr_matrix_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_INTMTX_LINK(0), DR_REG_INTERRUPT_MATRIX_BASE, DR_REG_INTERRUPT_MATRIX_BASE, N_REGS_INTR_MATRIX(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* intr matrix */
};
esp_err_t err = sleep_retention_entries_create(intr_matrix_regs_retention, ARRAY_SIZE(intr_matrix_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_INTR_MATRIX);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (Interrupt matrix) retention");
ESP_LOGI(TAG, "Interrupt Matrix sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_hp_system_retention_init(void)
{
#define N_REGS_HP_SYSTEM() (((HP_SYSTEM_MEM_TEST_CONF_REG - DR_REG_HP_SYSTEM_BASE) / 4) + 1)
const static sleep_retention_entries_config_t hp_system_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_HPSYS_LINK(0), DR_REG_HP_SYSTEM_BASE, DR_REG_HP_SYSTEM_BASE, N_REGS_HP_SYSTEM(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* hp system */
};
esp_err_t err = sleep_retention_entries_create(hp_system_regs_retention, ARRAY_SIZE(hp_system_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_HP_SYSTEM);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (HP system) retention");
ESP_LOGI(TAG, "HP System sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_tee_apm_retention_init(void)
{
#define N_REGS_TEE() (((TEE_CLOCK_GATE_REG - DR_REG_TEE_BASE) / 4) + 1)
#define N_REGS_APM() (((HP_APM_CLOCK_GATE_REG - DR_REG_HP_APM_BASE) / 4) + 1)
const static sleep_retention_entries_config_t tee_apm_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TEEAPM_LINK(0), DR_REG_TEE_BASE, DR_REG_TEE_BASE, N_REGS_TEE(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* tee */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TEEAPM_LINK(0), DR_REG_HP_APM_BASE, DR_REG_HP_APM_BASE, N_REGS_APM(), 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* apm */
};
esp_err_t err = sleep_retention_entries_create(tee_apm_regs_retention, ARRAY_SIZE(tee_apm_regs_retention), REGDMA_LINK_PRI_4, SLEEP_RETENTION_MODULE_TEE_APM);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (TEE/APM) retention");
ESP_LOGI(TAG, "TEE/APM sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_uart0_retention_init(void)
{
#define N_REGS_UART() (((UART_ID_REG(0) - REG_UART_BASE(0)) / 4) + 1)
const static sleep_retention_entries_config_t uart_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), REG_UART_BASE(0), REG_UART_BASE(0), N_REGS_UART(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* uart */
/* Note: uart register should set update reg to make the configuration take effect */
[1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_UART_LINK(0x01), UART_REG_UPDATE_REG(0), UART_REG_UPDATE, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_UART_LINK(0x02), UART_REG_UPDATE_REG(0), 0x0, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }
};
esp_err_t err = sleep_retention_entries_create(uart_regs_retention, ARRAY_SIZE(uart_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_UART0);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (UART) retention");
ESP_LOGI(TAG, "UART sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_tg0_retention_init(void)
{
#define N_REGS_TG() (((TIMG_REGCLK_REG(0) - REG_TIMG_BASE(0)) / 4) + 1)
const static sleep_retention_entries_config_t tg_regs_retention[] = {
/*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/
[0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, /* TG0 */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x01), REG_TIMG_BASE(0), REG_TIMG_BASE(0), N_REGS_TG(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x02), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x04), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) },
[5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_TIMG_LINK(0x05), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) },
[6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x06), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x07), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }
};
esp_err_t err = sleep_retention_entries_create(tg_regs_retention, ARRAY_SIZE(tg_regs_retention), SLEEP_RETENTION_PERIPHERALS_PRIORITY_DEFAULT, SLEEP_RETENTION_MODULE_TG0);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (Timer Group) retention");
ESP_LOGI(TAG, "Timer Group sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_iomux_retention_init(void)
{
#define N_REGS_IOMUX_0() (((PERIPHS_IO_MUX_SPID_U - REG_IO_MUX_BASE) / 4) + 1)
#define N_REGS_IOMUX_1() (((GPIO_FUNC34_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1)
#define N_REGS_IOMUX_2() (((GPIO_FUNC124_IN_SEL_CFG_REG - GPIO_STATUS_NEXT_REG) / 4) + 1)
#define N_REGS_IOMUX_3() (((GPIO_PIN34_REG - DR_REG_GPIO_BASE) / 4) + 1)
const static sleep_retention_entries_config_t iomux_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* io_mux */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x01), GPIO_FUNC0_OUT_SEL_CFG_REG, GPIO_FUNC0_OUT_SEL_CFG_REG, N_REGS_IOMUX_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x02), GPIO_STATUS_NEXT_REG, GPIO_STATUS_NEXT_REG, N_REGS_IOMUX_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x03), DR_REG_GPIO_BASE, DR_REG_GPIO_BASE, N_REGS_IOMUX_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }
};
esp_err_t err = sleep_retention_entries_create(iomux_regs_retention, ARRAY_SIZE(iomux_regs_retention), SLEEP_RETENTION_PERIPHERALS_PRIORITY_DEFAULT, SLEEP_RETENTION_MODULE_IOMUX);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (IO Matrix) retention");
ESP_LOGI(TAG, "IO Matrix sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_spimem_retention_init(void)
{
#define N_REGS_SPI1_MEM_0() (((SPI_MEM_SPI_SMEM_DDR_REG(1) - REG_SPI_MEM_BASE(1)) / 4) + 1)
#define N_REGS_SPI1_MEM_1() (((SPI_MEM_SPI_SMEM_AC_REG(1) - SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1)) / 4) + 1)
#define N_REGS_SPI1_MEM_2() (1)
#define N_REGS_SPI1_MEM_3() (((SPI_MEM_DATE_REG(1) - SPI_MEM_DPA_CTRL_REG(1)) / 4) + 1)
#define N_REGS_SPI0_MEM_0() (((SPI_MEM_SPI_SMEM_DDR_REG(0) - REG_SPI_MEM_BASE(0)) / 4) + 1)
#define N_REGS_SPI0_MEM_1() (((SPI_MEM_SPI_SMEM_AC_REG(0) - SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(0)) / 4) + 1)
#define N_REGS_SPI0_MEM_2() (1)
#define N_REGS_SPI0_MEM_3() (((SPI_MEM_DATE_REG(0) - SPI_MEM_DPA_CTRL_REG(0)) / 4) + 1)
const static sleep_retention_entries_config_t spimem_regs_retention[] = {
/* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x00), REG_SPI_MEM_BASE(1), REG_SPI_MEM_BASE(1), N_REGS_SPI1_MEM_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* spi1_mem */
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x01), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1), N_REGS_SPI1_MEM_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x02), SPI_MEM_CLOCK_GATE_REG(1), SPI_MEM_CLOCK_GATE_REG(1), N_REGS_SPI1_MEM_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x03), SPI_MEM_DPA_CTRL_REG(1), SPI_MEM_DPA_CTRL_REG(1), N_REGS_SPI1_MEM_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
/* Note: SPI mem should not to write mmu SPI_MEM_MMU_ITEM_CONTENT_REG and SPI_MEM_MMU_ITEM_INDEX_REG */
[4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x04), REG_SPI_MEM_BASE(0), REG_SPI_MEM_BASE(0), N_REGS_SPI0_MEM_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* spi0_mem */
[5] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x05), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(0), SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(0), N_REGS_SPI0_MEM_1(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x06), SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLOCK_GATE_REG(0), N_REGS_SPI0_MEM_2(), 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x07), SPI_MEM_DPA_CTRL_REG(0), SPI_MEM_DPA_CTRL_REG(0), N_REGS_SPI0_MEM_3(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }
};
esp_err_t err = sleep_retention_entries_create(spimem_regs_retention, ARRAY_SIZE(spimem_regs_retention), SLEEP_RETENTION_PERIPHERALS_PRIORITY_DEFAULT, SLEEP_RETENTION_MODULE_SPIMEM);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (SPI mem) retention");
ESP_LOGI(TAG, "SPI Mem sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_systimer_retention_init(void)
{
#define N_REGS_SYSTIMER_0() (((SYSTIMER_TARGET2_CONF_REG - SYSTIMER_TARGET0_HI_REG) / 4) + 1)
const static sleep_retention_entries_config_t systimer_regs_retention[] = {
[0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x00), SYSTIMER_UNIT0_OP_REG, SYSTIMER_TIMER_UNIT0_UPDATE_M, SYSTIMER_TIMER_UNIT0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, /* Systimer */
[1] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_SYSTIMER_LINK(0x01), SYSTIMER_UNIT0_OP_REG, SYSTIMER_TIMER_UNIT0_VALUE_VALID, SYSTIMER_TIMER_UNIT0_VALUE_VALID, 0, 1), .owner = ENTRY(0) | ENTRY(2) },
[2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x02), SYSTIMER_UNIT0_VALUE_HI_REG, SYSTIMER_UNIT0_LOAD_HI_REG, 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x03), SYSTIMER_UNIT0_LOAD_REG, SYSTIMER_TIMER_UNIT0_LOAD_M, SYSTIMER_TIMER_UNIT0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x04), SYSTIMER_UNIT1_OP_REG, SYSTIMER_TIMER_UNIT1_UPDATE_M, SYSTIMER_TIMER_UNIT1_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) },
[5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_SYSTIMER_LINK(0x05), SYSTIMER_UNIT1_OP_REG, SYSTIMER_TIMER_UNIT1_VALUE_VALID, SYSTIMER_TIMER_UNIT1_VALUE_VALID, 0, 1), .owner = ENTRY(0) | ENTRY(2) },
[6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x06), SYSTIMER_UNIT1_VALUE_HI_REG, SYSTIMER_UNIT1_LOAD_HI_REG, 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) },
[7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x07), SYSTIMER_UNIT1_LOAD_REG, SYSTIMER_TIMER_UNIT1_LOAD_M, SYSTIMER_TIMER_UNIT1_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[8] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x08), SYSTIMER_TARGET0_HI_REG, SYSTIMER_TARGET0_HI_REG, N_REGS_SYSTIMER_0(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* Systimer target value & period */
[9] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x09), SYSTIMER_COMP0_LOAD_REG, SYSTIMER_TIMER_COMP0_LOAD, SYSTIMER_TIMER_COMP0_LOAD, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[10] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x0a), SYSTIMER_COMP1_LOAD_REG, SYSTIMER_TIMER_COMP1_LOAD, SYSTIMER_TIMER_COMP1_LOAD, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[11] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x0b), SYSTIMER_COMP2_LOAD_REG, SYSTIMER_TIMER_COMP2_LOAD, SYSTIMER_TIMER_COMP2_LOAD, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[12] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x0c), SYSTIMER_TARGET0_CONF_REG, 0, SYSTIMER_TARGET0_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[13] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x0d), SYSTIMER_TARGET0_CONF_REG, SYSTIMER_TARGET0_PERIOD_MODE_M, SYSTIMER_TARGET0_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[14] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x0e), SYSTIMER_TARGET1_CONF_REG, 0, SYSTIMER_TARGET1_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[15] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x0f), SYSTIMER_TARGET1_CONF_REG, SYSTIMER_TARGET1_PERIOD_MODE_M, SYSTIMER_TARGET1_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[16] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_SYSTIMER_LINK(0x10), SYSTIMER_TARGET2_CONF_REG, 0, SYSTIMER_TARGET2_PERIOD_MODE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) },
[17] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x11), SYSTIMER_CONF_REG, SYSTIMER_CONF_REG, 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* Systimer work enable */
[18] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x12), SYSTIMER_INT_ENA_REG, SYSTIMER_INT_ENA_REG, 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* Systimer intr enable */
};
esp_err_t err = sleep_retention_entries_create(systimer_regs_retention, ARRAY_SIZE(systimer_regs_retention), SLEEP_RETENTION_PERIPHERALS_PRIORITY_DEFAULT, SLEEP_RETENTION_MODULE_SYSTIMER);
ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (SysTimer) retention");
ESP_LOGI(TAG, "SysTimer sleep retention initialization");
return ESP_OK;
}
esp_err_t sleep_peripheral_retention_init(void)
{
esp_err_t err;
err = sleep_peripheral_intr_matrix_retention_init();
if(err) goto error;
err = sleep_peripheral_hp_system_retention_init();
if(err) goto error;
err = sleep_peripheral_tee_apm_retention_init();
if(err) goto error;
err = sleep_peripheral_uart0_retention_init();
if(err) goto error;
err = sleep_peripheral_tg0_retention_init();
if(err) goto error;
err = sleep_peripheral_iomux_retention_init();
if(err) goto error;
err = sleep_peripheral_spimem_retention_init();
if(err) goto error;
err = sleep_peripheral_systimer_retention_init();
error:
return err;
}
bool IRAM_ATTR peripheral_domain_pd_allowed(void)
{
const uint32_t modules = sleep_retention_get_modules();
const uint32_t mask = (const uint32_t) (
SLEEP_RETENTION_MODULE_INTR_MATRIX | \
SLEEP_RETENTION_MODULE_HP_SYSTEM | \
SLEEP_RETENTION_MODULE_TEE_APM | \
SLEEP_RETENTION_MODULE_UART0 | \
SLEEP_RETENTION_MODULE_TG0 | \
SLEEP_RETENTION_MODULE_IOMUX | \
SLEEP_RETENTION_MODULE_SPIMEM | \
SLEEP_RETENTION_MODULE_SYSTIMER);
return ((modules & mask) == mask);
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
ESP_SYSTEM_INIT_FN(sleep_peripheral_startup_init, BIT(0), 107)
{
sleep_peripheral_retention_init();
return ESP_OK;
}
#endif

View File

@@ -0,0 +1,463 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "soc/soc_caps.h"
#include "esp_private/esp_regdma.h"
#include "esp_private/esp_pau.h"
#include "esp_private/sleep_retention.h"
#include "sdkconfig.h"
#include "esp_pmu.h"
static __attribute__((unused)) const char *TAG = "sleep";
/**
* Internal structure which holds all requested sleep retention parameters
*/
typedef struct {
/* The hardware retention module (REGDMA and PMU) uses 4 linked lists to
* record the hardware context information that needs to be backed up and
* restored when switching between different power states. The 4 linked
* lists are linked by 8 types of nodes. The 4 linked lists can reuse some
* nodes with each other, or separate their own unique nodes after branch
* type nodes.
* The REGDMA module iterates the entire linked list from the head of a
* linked list and backs up and restores the corresponding register context
* information according to the configuration information of the linked list
* nodes.
* The PMU module triggers REGDMA to use the corresponding linked list when
* swtiching between different power states. For example:
*
* Current power state Next power state This entry will be used by REGDMA
* PMU_HP_ACTIVE PMU_HP_SLEEP entry0
* PMU_HP_SLEEP PMU_HP_ACTIVE entry0
* PMU_HP_MODEM PMU_HP_SLEEP entry1
* PMU_HP_SLEEP PMU_HP_MODEM entry1
* PMU_HP_MODEM PMU_HP_ACTIVE entry2
*
* +--------+ +-------------------------+ +-------------+ +-----------+ +--------+ +-----+
* entry2 -> | | -> | WiFi MAC Minimum System | -> | | -------------------------> | | -> | | -> | End |
* | SOC | +-------------------------+ | Digital | | Bluetooth | | Zigbee | +-----+
* | System | +--------+ | Peripherals | +------+ +------+ | / BLE | | | +-----+
* entry0 -> | | ----------> | | ---------> | | -> | | -> | | -> | | -> | | -> | End |
* +--------+ | Modem | +-------------+ | WiFi | | WiFi | +-----------+ +--------+ +-----+
* | System | | MAC | | BB | +-----+
* entry1 ------------------------> | |-----------------------------> | | -> | | -> | End |
* +--------+ +------+ +------+ +-----+
*/
#define SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES (8u)
#define SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY (0)
#define SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY (SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES - 1)
struct {
sleep_retention_entries_t entries;
uint32_t entries_bitmap: REGDMA_LINK_ENTRY_NUM,
runtime_bitmap: REGDMA_LINK_ENTRY_NUM,
reserved: 32-(2*REGDMA_LINK_ENTRY_NUM);
void *entries_tail;
} lists[SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES];
_lock_t lock;
regdma_link_priority_t highpri;
uint32_t modules;
} sleep_retention_t;
static DRAM_ATTR __attribute__((unused)) sleep_retention_t s_retention = { .highpri = (uint8_t)-1, .modules = 0 };
#define SLEEP_RETENTION_ENTRY_BITMAP_MASK (BIT(REGDMA_LINK_ENTRY_NUM) - 1)
#define SLEEP_RETENTION_ENTRY_BITMAP(bitmap) ((bitmap) & SLEEP_RETENTION_ENTRY_BITMAP_MASK)
static esp_err_t sleep_retention_entries_create_impl(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, int module);
static void sleep_retention_entries_join(void);
static inline bool sleep_retention_entries_require_branch(uint32_t owner, uint32_t runtime_bitmap)
{
bool use_new_entry = SLEEP_RETENTION_ENTRY_BITMAP(owner & ~runtime_bitmap) ? true : false;
bool intersection_exist = SLEEP_RETENTION_ENTRY_BITMAP(owner & runtime_bitmap) ? true : false;
return use_new_entry && intersection_exist;
}
static esp_err_t sleep_retention_entries_check_and_create_default(uint32_t owner, uint32_t runtime_bitmap, uint32_t entries_bitmap, regdma_link_priority_t priority, uint32_t module)
{
assert(sleep_retention_entries_require_branch(owner, runtime_bitmap));
static sleep_retention_entries_config_t dummy = { REGDMA_LINK_WAIT_INIT(0xffff, 0, 0, 0, 1, 1), 0 };
dummy.owner = SLEEP_RETENTION_ENTRY_BITMAP(owner & ~entries_bitmap);
if (dummy.owner) {
return sleep_retention_entries_create_impl(&dummy, 1, priority, module);
}
return ESP_OK;
}
static esp_err_t sleep_retention_entries_check_and_create_final_default(void)
{
static const sleep_retention_entries_config_t final_dummy = { REGDMA_LINK_WAIT_INIT(0xffff, 0, 0, 0, 1, 1), SLEEP_RETENTION_ENTRY_BITMAP_MASK };
esp_err_t err = ESP_OK;
_lock_acquire_recursive(&s_retention.lock);
if (s_retention.lists[SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY].entries_bitmap == 0) {
err = sleep_retention_entries_create_impl(&final_dummy, 1, SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY, 0);
}
_lock_release_recursive(&s_retention.lock);
return err;
}
static void sleep_retention_entries_update(uint32_t owner, void *new_link, regdma_link_priority_t priority)
{
_lock_acquire_recursive(&s_retention.lock);
sleep_retention_entries_t retention_entries = {
(owner & BIT(0)) ? new_link : s_retention.lists[priority].entries[0],
(owner & BIT(1)) ? new_link : s_retention.lists[priority].entries[1],
(owner & BIT(2)) ? new_link : s_retention.lists[priority].entries[2],
(owner & BIT(3)) ? new_link : s_retention.lists[priority].entries[3]
};
if (s_retention.lists[priority].entries_bitmap == 0) {
s_retention.lists[priority].entries_tail = new_link;
}
memcpy(s_retention.lists[priority].entries, retention_entries, sizeof(sleep_retention_entries_t));
s_retention.lists[priority].runtime_bitmap = owner;
s_retention.lists[priority].entries_bitmap |= owner;
_lock_release_recursive(&s_retention.lock);
}
static void * sleep_retention_entries_try_create(const regdma_link_config_t *config, uint32_t owner, regdma_link_priority_t priority, uint32_t module)
{
void *link = NULL;
assert(owner > 0 && owner < BIT(REGDMA_LINK_ENTRY_NUM));
_lock_acquire_recursive(&s_retention.lock);
if (sleep_retention_entries_require_branch(owner, s_retention.lists[priority].runtime_bitmap)) {
if (sleep_retention_entries_check_and_create_default(owner, s_retention.lists[priority].runtime_bitmap,
s_retention.lists[priority].entries_bitmap, priority, module) == ESP_OK) { /* branch node can't as tail node */
link = regdma_link_init_safe(
config, true, module,
(owner & BIT(0)) ? s_retention.lists[priority].entries[0] : NULL,
(owner & BIT(1)) ? s_retention.lists[priority].entries[1] : NULL,
(owner & BIT(2)) ? s_retention.lists[priority].entries[2] : NULL,
(owner & BIT(3)) ? s_retention.lists[priority].entries[3] : NULL
);
}
} else {
link = regdma_link_init_safe(config, false, module, s_retention.lists[priority].entries[__builtin_ffs(owner) - 1]);
}
_lock_release_recursive(&s_retention.lock);
return link;
}
static void * sleep_retention_entries_try_create_bonding(const regdma_link_config_t *config, uint32_t owner, regdma_link_priority_t priority, uint32_t module)
{
assert(owner > 0 && owner < BIT(REGDMA_LINK_ENTRY_NUM));
_lock_acquire_recursive(&s_retention.lock);
void *link = regdma_link_init_safe(
config, true, module,
(owner & BIT(0)) ? s_retention.lists[priority].entries[0] : NULL,
(owner & BIT(1)) ? s_retention.lists[priority].entries[1] : NULL,
(owner & BIT(2)) ? s_retention.lists[priority].entries[2] : NULL,
(owner & BIT(3)) ? s_retention.lists[priority].entries[3] : NULL
);
_lock_release_recursive(&s_retention.lock);
return link;
}
static void sleep_retention_entries_stats(void)
{
_lock_acquire_recursive(&s_retention.lock);
if (s_retention.highpri >= SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY && s_retention.highpri <= SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY) {
for (int entry = 0; entry < ARRAY_SIZE(s_retention.lists[s_retention.highpri].entries); entry++) {
regdma_link_stats(s_retention.lists[s_retention.highpri].entries[entry], entry);
}
}
_lock_release_recursive(&s_retention.lock);
}
#if REGDMA_LINK_DBG
void sleep_retention_entries_show_memories(void)
{
if (&s_retention.lock) {
_lock_acquire_recursive(&s_retention.lock);
if (s_retention.highpri >= SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY && s_retention.highpri <= SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY) {
for (int entry = 0; entry < ARRAY_SIZE(s_retention.lists[s_retention.highpri].entries); entry++) {
ESP_LOGW(TAG, "Print sleep retention entries[%d] memories:", entry);
regdma_link_show_memories(s_retention.lists[s_retention.highpri].entries[entry], entry);
}
}
_lock_release_recursive(&s_retention.lock);
}
}
#endif
void * sleep_retention_find_link_by_id(int id)
{
void *link = NULL;
if (&s_retention.lock) {
_lock_acquire_recursive(&s_retention.lock);
if (s_retention.highpri >= SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY &&
s_retention.highpri <= SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY) {
for (int entry = 0; (link == NULL && entry < ARRAY_SIZE(s_retention.lists[s_retention.highpri].entries)); entry++) {
link = regdma_find_link_by_id(s_retention.lists[s_retention.highpri].entries[entry], entry, id);
}
}
_lock_release_recursive(&s_retention.lock);
}
return link;
}
static uint32_t sleep_retention_entries_owner_bitmap(sleep_retention_entries_t *entries, sleep_retention_entries_t *tails)
{
uint32_t owner = 0;
_lock_acquire_recursive(&s_retention.lock);
for (int entry = 0; entry < ARRAY_SIZE(*entries); entry++) {
owner |= regdma_link_get_owner_bitmap((*entries)[entry], (*tails)[entry], entry);
}
_lock_release_recursive(&s_retention.lock);
return owner;
}
static bool sleep_retention_entries_get_destroy_context(regdma_link_priority_t priority, uint32_t module, sleep_retention_entries_t *destroy_entries, void **destroy_tail, sleep_retention_entries_t *next_entries, void **prev_tail)
{
bool exist = false;
sleep_retention_entries_t destroy_tails, prev_tails;
memset(&destroy_tails, 0, sizeof(sleep_retention_entries_t));
memset(&prev_tails, 0, sizeof(sleep_retention_entries_t));
_lock_acquire_recursive(&s_retention.lock);
for (int entry = 0; entry < ARRAY_SIZE(s_retention.lists[priority].entries); entry++) {
(*destroy_entries)[entry] = regdma_find_module_link_head(
s_retention.lists[priority].entries[entry], s_retention.lists[priority].entries_tail, entry, module);
destroy_tails [entry] = regdma_find_module_link_tail(
s_retention.lists[priority].entries[entry], s_retention.lists[priority].entries_tail, entry, module);
(*next_entries) [entry] = regdma_find_next_module_link_head(
s_retention.lists[priority].entries[entry], s_retention.lists[priority].entries_tail, entry, module);
prev_tails [entry] = regdma_find_prev_module_link_tail(
s_retention.lists[priority].entries[entry], s_retention.lists[priority].entries_tail, entry, module);
if ((*destroy_entries)[entry] && destroy_tails[entry]) {
exist = true;
}
assert(destroy_tails[entry] == destroy_tails[0]);
assert(prev_tails[entry] == prev_tails[0]);
}
*destroy_tail = destroy_tails[0];
*prev_tail = prev_tails[0];
_lock_release_recursive(&s_retention.lock);
return exist;
}
static void sleep_retention_entries_context_update(regdma_link_priority_t priority)
{
_lock_acquire_recursive(&s_retention.lock);
sleep_retention_entries_t tails = {
s_retention.lists[priority].entries_tail, s_retention.lists[priority].entries_tail,
s_retention.lists[priority].entries_tail, s_retention.lists[priority].entries_tail
};
s_retention.lists[priority].entries_bitmap = sleep_retention_entries_owner_bitmap(&s_retention.lists[priority].entries, &tails);
s_retention.lists[priority].runtime_bitmap = sleep_retention_entries_owner_bitmap(&s_retention.lists[priority].entries, &s_retention.lists[priority].entries);
_lock_release_recursive(&s_retention.lock);
}
static bool sleep_retention_entries_dettach(regdma_link_priority_t priority, sleep_retention_entries_t *destroy_entries, void *destroy_tail, sleep_retention_entries_t *next_entries, void *prev_tail)
{
_lock_acquire_recursive(&s_retention.lock);
bool is_head = (memcmp(destroy_entries, &s_retention.lists[priority].entries, sizeof(sleep_retention_entries_t)) == 0);
bool is_tail = (destroy_tail == s_retention.lists[priority].entries_tail);
if (is_head && is_tail) {
memset(s_retention.lists[priority].entries, 0, sizeof(sleep_retention_entries_t));
s_retention.lists[priority].entries_tail = NULL;
} else if (is_head) {
memcpy(&s_retention.lists[priority].entries, next_entries, sizeof(sleep_retention_entries_t));
} else if (is_tail) {
s_retention.lists[priority].entries_tail = prev_tail;
} else {
regdma_link_update_next_safe(prev_tail, (*next_entries)[0], (*next_entries)[1], (*next_entries)[2], (*next_entries)[3]);
}
sleep_retention_entries_context_update(priority);
regdma_link_update_next_safe(destroy_tail, NULL, NULL, NULL, NULL);
_lock_release_recursive(&s_retention.lock);
return (is_head || is_tail);
}
static void sleep_retention_entries_destroy_wrapper(sleep_retention_entries_t *destroy_entries)
{
for (int entry = 0; entry < ARRAY_SIZE(*destroy_entries); entry++) {
regdma_link_destroy((*destroy_entries)[entry], entry);
}
}
static void sleep_retention_entries_check_and_distroy_final_default(void)
{
_lock_acquire_recursive(&s_retention.lock);
assert(s_retention.highpri == SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY);
assert(s_retention.modules == 0);
sleep_retention_entries_destroy_wrapper(&s_retention.lists[SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY].entries);
_lock_release_recursive(&s_retention.lock);
}
static void sleep_retention_entries_all_destroy_wrapper(uint32_t module)
{
void *destroy_tail = NULL, *prev_tail = NULL;
sleep_retention_entries_t destroy_entries, next_entries;
memset(&destroy_entries, 0, sizeof(sleep_retention_entries_t));
memset(&next_entries, 0, sizeof(sleep_retention_entries_t));
_lock_acquire_recursive(&s_retention.lock);
regdma_link_priority_t priority = 0;
do {
bool exist = sleep_retention_entries_get_destroy_context(priority, module, &destroy_entries, &destroy_tail, &next_entries, &prev_tail);
if (s_retention.lists[priority].entries_bitmap && exist) {
if (sleep_retention_entries_dettach(priority, &destroy_entries, destroy_tail, &next_entries, prev_tail)) {
sleep_retention_entries_join();
}
sleep_retention_entries_destroy_wrapper(&destroy_entries);
} else {
priority++;
}
} while (priority < SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES);
s_retention.modules &= ~module;
_lock_release_recursive(&s_retention.lock);
}
void sleep_retention_entries_destroy(int module)
{
assert(module != 0);
if (&s_retention.lock) {
_lock_acquire_recursive(&s_retention.lock);
sleep_retention_entries_join();
sleep_retention_entries_stats();
sleep_retention_entries_all_destroy_wrapper(module);
if (s_retention.modules == 0) {
sleep_retention_entries_check_and_distroy_final_default();
pmu_sleep_disable_regdma_backup();
memset((void *)s_retention.lists, 0, sizeof(s_retention.lists));
s_retention.highpri = (uint8_t)-1;
_lock_release_recursive(&s_retention.lock);
_lock_close_recursive(&s_retention.lock);
s_retention.lock = NULL;
return;
}
_lock_acquire_recursive(&s_retention.lock);
}
}
static esp_err_t sleep_retention_entries_create_impl(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, int module)
{
_lock_acquire_recursive(&s_retention.lock);
for (int i = num - 1; i >= 0; i--) {
void *link = sleep_retention_entries_try_create(&retent[i].config, retent[i].owner, priority, module);
if (link == NULL) {
_lock_release_recursive(&s_retention.lock);
sleep_retention_entries_destroy(module);
return ESP_ERR_NO_MEM;
}
sleep_retention_entries_update(retent[i].owner, link, priority);
}
_lock_release_recursive(&s_retention.lock);
return ESP_OK;
}
static esp_err_t sleep_retention_entries_create_bonding(regdma_link_priority_t priority, uint32_t module)
{
static const sleep_retention_entries_config_t bonding_dummy = { REGDMA_LINK_WAIT_INIT(0xffff, 0, 0, 0, 1, 1), SLEEP_RETENTION_ENTRY_BITMAP_MASK };
_lock_acquire_recursive(&s_retention.lock);
void *link = sleep_retention_entries_try_create_bonding(&bonding_dummy.config, bonding_dummy.owner, priority, module);
if (link == NULL) {
_lock_release_recursive(&s_retention.lock);
sleep_retention_entries_destroy(module);
return ESP_ERR_NO_MEM;
}
sleep_retention_entries_update(bonding_dummy.owner, link, priority);
_lock_release_recursive(&s_retention.lock);
return ESP_OK;
}
static void sleep_retention_entries_join(void)
{
void *entries_tail = NULL;
_lock_acquire_recursive(&s_retention.lock);
s_retention.highpri = SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY;
for (regdma_link_priority_t priority = 0; priority < SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES; priority++) {
if (s_retention.lists[priority].entries_bitmap == 0) continue;
if (priority < s_retention.highpri) { s_retention.highpri = priority; }
if (entries_tail) {
regdma_link_update_next_safe(
entries_tail,
s_retention.lists[priority].entries[0],
s_retention.lists[priority].entries[1],
s_retention.lists[priority].entries[2],
s_retention.lists[priority].entries[3]
);
}
entries_tail = s_retention.lists[priority].entries_tail;
}
pau_regdma_set_entry_link_addr(&(s_retention.lists[s_retention.highpri].entries));
_lock_release_recursive(&s_retention.lock);
}
static esp_err_t sleep_retention_entries_create_wrapper(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, uint32_t module)
{
_lock_acquire_recursive(&s_retention.lock);
esp_err_t err = sleep_retention_entries_create_bonding(priority, module);
if(err) goto error;
err = sleep_retention_entries_create_impl(retent, num, priority, module);
if(err) goto error;
err = sleep_retention_entries_create_bonding(priority, module);
if(err) goto error;
s_retention.modules |= module;
sleep_retention_entries_join();
error:
_lock_release_recursive(&s_retention.lock);
return err;
}
esp_err_t sleep_retention_entries_create(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, int module)
{
if (!(retent && num > 0 && (priority < SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES) && (module != 0))) {
return ESP_ERR_INVALID_ARG;
}
if (s_retention.lock == NULL) {
_lock_init_recursive(&s_retention.lock);
if (s_retention.lock == NULL) {
ESP_LOGE(TAG, "Create sleep retention lock failed");
return ESP_ERR_NO_MEM;
}
}
esp_err_t err = sleep_retention_entries_check_and_create_final_default();
if (err) goto error;
err = sleep_retention_entries_create_wrapper(retent, num, priority, module);
if (err) goto error;
pmu_sleep_enable_regdma_backup();
error:
return err;
}
void sleep_retention_entries_get(sleep_retention_entries_t *entries)
{
memset(entries, 0, sizeof(sleep_retention_entries_t));
if (&s_retention.lock) {
_lock_acquire_recursive(&s_retention.lock);
if (s_retention.highpri >= SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY &&
s_retention.highpri <= SLEEP_RETENTION_REGDMA_LINK_LOWEST_PRIORITY) {
memcpy(entries, &s_retention.lists[s_retention.highpri].entries, sizeof(sleep_retention_entries_t));
}
_lock_release_recursive(&s_retention.lock);
}
}
uint32_t IRAM_ATTR sleep_retention_get_modules(void)
{
return s_retention.modules;
}

View File

@@ -104,6 +104,15 @@ menu "Power Management"
If enabled, the I/D-cache tag memory will be retained in light sleep. Depending on the the
cache configuration, if this option is enabled, it will consume up to 9 KB of internal RAM.
config PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
bool "Power down Digital Peripheral in light sleep"
depends on SOC_PAU_SUPPORTED
default n #TODO: enable by default if periph init/deinit management supported (WIFI-5252)
help
If enabled, the minimum digital peripheral register context to keep the system running is saved
and will reduce sleep current consumption by about 100 uA. enabling this option will consume
at least 4.55 KB of internal RAM.
config PM_UPDATE_CCOMPARE_HLI_WORKAROUND
bool
default y if PM_ENABLE && BTDM_CTRL_HLI

View File

@@ -18,6 +18,8 @@
# esp_sleep doesn't have init dependencies
105: esp_sleep_startup_init in components/esp_hw_support/sleep_gpio.c on BIT(0)
106: sleep_clock_startup_init in components/esp_hw_support/sleep_clock.c on BIT(0)
107: sleep_peripheral_startup_init in components/esp_hw_support/sleep_peripheral.c on BIT(0)
# app_trace has to be initialized before systemview
115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES

View File

@@ -131,6 +131,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "${target}/lp_timer_hal.c")
endif()
if(CONFIG_SOC_PAU_SUPPORTED)
list(APPEND srcs "${target}/pau_hal.c")
endif()
if(CONFIG_SOC_BOD_SUPPORTED)
list(APPEND srcs "brownout_hal.c")
endif()

View File

@@ -74,6 +74,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return PCR_TSENS_CLK_EN;
case PERIPH_SDIO_SLAVE_MODULE:
return PCR_SDIO_SLAVE_CLK_EN;
case PERIPH_REGDMA_MODULE:
return PCR_REGDMA_CLK_EN;
// case PERIPH_RNG_MODULE:
// return PCR_WIFI_CLK_RNG_EN;
// case PERIPH_WIFI_MODULE:
@@ -163,6 +165,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return PCR_DS_RST_EN;
case PERIPH_SDIO_SLAVE_MODULE:
return PCR_SDIO_SLAVE_RST_EN;
case PERIPH_REGDMA_MODULE:
return PCR_REGDMA_RST_EN;
// case PERIPH_RNG_MODULE:
// return PCR_WIFI_CLK_RNG_EN;
// case PERIPH_WIFI_MODULE:
@@ -245,6 +249,8 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
return PCR_TSENS_CLK_CONF_REG;
case PERIPH_SDIO_SLAVE_MODULE:
return PCR_SDIO_SLAVE_CONF_REG;
case PERIPH_REGDMA_MODULE:
return PCR_REGDMA_CONF_REG;
default:
return 0;
}
@@ -307,6 +313,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
return PCR_TSENS_CLK_CONF_REG;
case PERIPH_SDIO_SLAVE_MODULE:
return PCR_SDIO_SLAVE_CONF_REG;
case PERIPH_REGDMA_MODULE:
return PCR_REGDMA_CONF_REG;
default:
return 0;
}

View File

@@ -0,0 +1,155 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for ESP32-C6 PAU(Power Assist Unit) register operations
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/pau_reg.h"
#include "soc/pau_struct.h"
#include "hal/pau_types.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline uint32_t pau_ll_get_regdma_backup_flow_error(pau_dev_t *dev)
{
return dev->regdma_conf.flow_err;
}
static inline void pau_ll_select_regdma_entry_link(pau_dev_t *dev, int link)
{
dev->regdma_conf.link_sel = link;
}
static inline void pau_ll_set_regdma_entry_link_backup_direction(pau_dev_t *dev, bool to_mem)
{
dev->regdma_conf.to_mem = to_mem ? 1 : 0;
}
static inline void pau_ll_set_regdma_entry_link_backup_start_enable(pau_dev_t *dev)
{
dev->regdma_conf.start = 1;
}
static inline void pau_ll_set_regdma_entry_link_backup_start_disable(pau_dev_t *dev)
{
dev->regdma_conf.start = 0;
}
static inline void pau_ll_set_regdma_select_wifimac_link(pau_dev_t *dev)
{
dev->regdma_conf.sel_mac = 1;
}
static inline void pau_ll_set_regdma_deselect_wifimac_link(pau_dev_t *dev)
{
dev->regdma_conf.sel_mac = 0;
}
static inline void pau_ll_set_regdma_wifimac_link_backup_direction(pau_dev_t *dev, bool to_mem)
{
dev->regdma_conf.to_mem_mac = to_mem ? 1 : 0;
}
static inline void pau_ll_set_regdma_wifimac_link_backup_start_enable(pau_dev_t *dev)
{
dev->regdma_conf.start_mac = 1;
}
static inline void pau_ll_set_regdma_wifimac_link_backup_start_disable(pau_dev_t *dev)
{
dev->regdma_conf.start_mac = 0;
}
static inline void pau_ll_set_regdma_link0_addr(pau_dev_t *dev, void *link_addr)
{
dev->regdma_link_0_addr.val = (uint32_t)link_addr;
}
static inline void pau_ll_set_regdma_link1_addr(pau_dev_t *dev, void *link_addr)
{
dev->regdma_link_1_addr.val = (uint32_t)link_addr;
}
static inline void pau_ll_set_regdma_link2_addr(pau_dev_t *dev, void *link_addr)
{
dev->regdma_link_2_addr.val = (uint32_t)link_addr;
}
static inline void pau_ll_set_regdma_link3_addr(pau_dev_t *dev, void *link_addr)
{
dev->regdma_link_3_addr.val = (uint32_t)link_addr;
}
static inline void pau_ll_set_regdma_wifimac_link_addr(pau_dev_t *dev, void *link_addr)
{
dev->regdma_link_mac_addr.val = (uint32_t)link_addr;
}
static inline uint32_t pau_ll_get_regdma_current_link_addr(pau_dev_t *dev)
{
return dev->regdma_current_link_addr.val;
}
static inline uint32_t pau_ll_get_regdma_backup_addr(pau_dev_t *dev)
{
return dev->regdma_backup_addr.val;
}
static inline uint32_t pau_ll_get_regdma_memory_addr(pau_dev_t *dev)
{
return dev->regdma_mem_addr.val;
}
static inline uint32_t pau_ll_get_regdma_intr_raw_signal(pau_dev_t *dev)
{
return dev->int_raw.val;
}
static inline uint32_t pau_ll_get_regdma_intr_status(pau_dev_t *dev)
{
return dev->int_st.val;
}
static inline void pau_ll_set_regdma_backup_done_intr_enable(pau_dev_t *dev)
{
dev->int_ena.done_int_ena = 1;
}
static inline void pau_ll_set_regdma_backup_done_intr_disable(pau_dev_t *dev)
{
dev->int_ena.done_int_ena = 0;
}
static inline void pau_ll_set_regdma_backup_error_intr_enable(pau_dev_t *dev)
{
dev->int_ena.error_int_ena = 1;
}
static inline void pau_ll_set_regdma_backup_error_intr_disable(pau_dev_t *dev)
{
dev->int_ena.error_int_ena = 0;
}
static inline void pau_ll_clear_regdma_backup_done_intr_state(pau_dev_t *dev)
{
dev->int_clr.done_int_clr = 1;
}
static inline void pau_ll_clear_regdma_backup_error_intr_state(pau_dev_t *dev)
{
dev->int_clr.error_int_clr = 1;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for PAU (ESP32-C6 specific part)
#include "soc/soc.h"
#include "esp_attr.h"
#include "hal/pau_hal.h"
#include "hal/pau_types.h"
void pau_hal_set_regdma_entry_link_addr(pau_hal_context_t *hal, pau_regdma_link_addr_t *link_addr)
{
pau_ll_set_regdma_link0_addr(hal->dev, (*link_addr)[0]);
pau_ll_set_regdma_link1_addr(hal->dev, (*link_addr)[1]);
pau_ll_set_regdma_link2_addr(hal->dev, (*link_addr)[2]);
/* The link 3 of REGDMA is reserved, PMU state switching will not use
* REGDMA link 3 */
}
void pau_hal_start_regdma_modem_link(pau_hal_context_t *hal, bool backup_or_restore)
{
pau_ll_clear_regdma_backup_done_intr_state(hal->dev);
pau_ll_set_regdma_select_wifimac_link(hal->dev);
pau_ll_set_regdma_wifimac_link_backup_direction(hal->dev, backup_or_restore);
pau_ll_set_regdma_wifimac_link_backup_start_enable(hal->dev);
while (!(pau_ll_get_regdma_intr_raw_signal(hal->dev) & PAU_DONE_INT_RAW));
}
void pau_hal_stop_regdma_modem_link(pau_hal_context_t *hal)
{
pau_ll_set_regdma_wifimac_link_backup_start_disable(hal->dev);
pau_ll_set_regdma_deselect_wifimac_link(hal->dev);
pau_ll_clear_regdma_backup_done_intr_state(hal->dev);
}
void pau_hal_start_regdma_extra_link(pau_hal_context_t *hal, bool backup_or_restore)
{
pau_ll_clear_regdma_backup_done_intr_state(hal->dev);
/* The link 3 of REGDMA is reserved, we use it as an extra linked list to
* provide backup and restore services for BLE, IEEE802.15.4 and possibly
* other modules */
pau_ll_select_regdma_entry_link(hal->dev, 3);
pau_ll_set_regdma_entry_link_backup_direction(hal->dev, true);
pau_ll_set_regdma_entry_link_backup_start_enable(hal->dev);
while (!(pau_ll_get_regdma_intr_raw_signal(hal->dev) & PAU_DONE_INT_RAW));
}
void pau_hal_stop_regdma_extra_link(pau_hal_context_t *hal)
{
pau_ll_set_regdma_entry_link_backup_start_disable(hal->dev);
pau_ll_select_regdma_entry_link(hal->dev, 0); /* restore link select to default */
pau_ll_clear_regdma_backup_done_intr_state(hal->dev);
}

View File

@@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for PAU (Power Assist Unit)
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
#include "hal/pau_ll.h"
#include "hal/pau_types.h"
typedef struct {
pau_dev_t *dev;
} pau_hal_context_t;
/**
* @brief Set regdma entry link address
*
* @param hal regdma hal context
* @param link_addr entry link address value
*/
void pau_hal_set_regdma_entry_link_addr(pau_hal_context_t *hal, pau_regdma_link_addr_t *link_addr);
/**
* @brief Set regdma modem link address
*
* @param hal regdma hal context
* @param link_addr modem link address value
*/
#define pau_hal_set_regdma_modem_link_addr(hal, addr) pau_ll_set_regdma_wifimac_link_addr((hal)->dev, (addr))
/**
* @brief Start transmission on regdma modem link
*
* @param hal regdma hal context
* @param backup_or_restore false:restore true:backup
*/
void pau_hal_start_regdma_modem_link(pau_hal_context_t *hal, bool backup_or_restore);
/**
* @brief Stop transmission on regdma modem link
*
* @param hal regdma hal context
*/
void pau_hal_stop_regdma_modem_link(pau_hal_context_t *hal);
/**
* @brief Set regdma extra link address
*
* @param hal regdma hal context
* @param link_addr extra link address value
*/
#define pau_hal_set_regdma_extra_link_addr(hal, addr) pau_ll_set_regdma_link3_addr(hal->dev, (addr))
/**
* @brief Start transmission on regdma extra link
*
* @param hal regdma hal context
* @param backup_or_restore false:restore true:backup
*/
void pau_hal_start_regdma_extra_link(pau_hal_context_t *hal, bool backup_or_restore);
/**
* @brief Stop transmission on regdma extra link
*
* @param hal regdma hal context
*/
void pau_hal_stop_regdma_extra_link(pau_hal_context_t *hal);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#define PAU_REGDMA_LINK_NUM (SOC_PM_PAU_LINK_NUM)
/**
* @brief PAU REGDMA all link address buffer
*/
typedef void * pau_regdma_link_addr_t[PAU_REGDMA_LINK_NUM];

View File

@@ -159,6 +159,10 @@ config SOC_PMU_SUPPORTED
bool
default y
config SOC_PAU_SUPPORTED
bool
default y
config SOC_LP_TIMER_SUPPORTED
bool
default y
@@ -1015,6 +1019,10 @@ config SOC_PM_SUPPORT_VDDSDIO_PD
bool
default y
config SOC_PM_SUPPORT_TOP_PD
bool
default y
config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
bool
default y
@@ -1023,6 +1031,10 @@ config SOC_PM_CPU_RETENTION_BY_SW
bool
default y
config SOC_PM_PAU_LINK_NUM
int
default 4
config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
bool
default y

View File

@@ -40,6 +40,7 @@ typedef enum {
PERIPH_SYSTIMER_MODULE,
PERIPH_SARADC_MODULE,
PERIPH_TEMPSENSOR_MODULE,
PERIPH_REGDMA_MODULE,
PERIPH_WIFI_MODULE,
PERIPH_BT_MODULE,
PERIPH_IEEE802154_MODULE,

View File

@@ -65,6 +65,7 @@
#define SOC_BOD_SUPPORTED 1
#define SOC_APM_SUPPORTED 1
#define SOC_PMU_SUPPORTED 1
#define SOC_PAU_SUPPORTED 1
#define SOC_LP_TIMER_SUPPORTED 1
/*-------------------------- XTAL CAPS ---------------------------------------*/
@@ -427,11 +428,14 @@
#define SOC_PM_SUPPORT_RC32K_PD (1)
#define SOC_PM_SUPPORT_RC_FAST_PD (1)
#define SOC_PM_SUPPORT_VDDSDIO_PD (1)
#define SOC_PM_SUPPORT_TOP_PD (1)
#define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!<Supports CRC only the stub code in RTC memory */
#define SOC_PM_CPU_RETENTION_BY_SW (1)
#define SOC_PM_PAU_LINK_NUM (4)
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1)
#define SOC_MODEM_CLOCK_IS_INDEPENDENT (1)