kopia lustrzana https://github.com/espressif/esp-idf
regdma: add regdma link operation api support
rodzic
d3e0e3e3b6
commit
8c18393d23
|
@ -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
|
||||
|
|
|
@ -74,7 +74,8 @@ if(NOT BOOTLOADER_BUILD)
|
|||
endif()
|
||||
|
||||
if(CONFIG_SOC_PAU_SUPPORTED)
|
||||
list(APPEND srcs "port/pau_regdma.c")
|
||||
list(APPEND srcs "port/pau_regdma.c"
|
||||
"port/regdma_link.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW)
|
||||
|
|
|
@ -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
|
|
@ -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__ */
|
|
@ -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
|
Ładowanie…
Reference in New Issue