mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-06 14:14:33 +02:00
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:
@@ -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
|
||||
|
@@ -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}
|
||||
|
64
components/esp_hw_support/include/esp_private/esp_pau.h
Normal file
64
components/esp_hw_support/include/esp_private/esp_pau.h
Normal 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
|
649
components/esp_hw_support/include/esp_private/esp_regdma.h
Normal file
649
components/esp_hw_support/include/esp_private/esp_regdma.h
Normal 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
|
199
components/esp_hw_support/include/esp_private/regdma_link.h
Normal file
199
components/esp_hw_support/include/esp_private/regdma_link.h
Normal 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__ */
|
64
components/esp_hw_support/include/esp_private/sleep_clock.h
Normal file
64
components/esp_hw_support/include/esp_private/sleep_clock.h
Normal 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
|
@@ -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
|
120
components/esp_hw_support/include/esp_private/sleep_retention.h
Normal file
120
components/esp_hw_support/include/esp_private/sleep_retention.h
Normal 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
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
75
components/esp_hw_support/port/pau_regdma.c
Normal file
75
components/esp_hw_support/port/pau_regdma.c
Normal 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);
|
||||
}
|
798
components/esp_hw_support/port/regdma_link.c
Normal file
798
components/esp_hw_support/port/regdma_link.c
Normal 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
|
87
components/esp_hw_support/sleep_clock.c
Normal file
87
components/esp_hw_support/sleep_clock.c
Normal 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
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
254
components/esp_hw_support/sleep_peripheral.c
Normal file
254
components/esp_hw_support/sleep_peripheral.c
Normal 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
|
463
components/esp_hw_support/sleep_retention.c
Normal file
463
components/esp_hw_support/sleep_retention.c
Normal 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;
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
|
@@ -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;
|
||||
}
|
||||
|
155
components/hal/esp32c6/include/hal/pau_ll.h
Normal file
155
components/hal/esp32c6/include/hal/pau_ll.h
Normal 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
|
58
components/hal/esp32c6/pau_hal.c
Normal file
58
components/hal/esp32c6/pau_hal.c
Normal 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);
|
||||
}
|
79
components/hal/include/hal/pau_hal.h
Normal file
79
components/hal/include/hal/pau_hal.h
Normal 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
|
16
components/hal/include/hal/pau_types.h
Normal file
16
components/hal/include/hal/pau_types.h
Normal 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];
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user