1 /*
2 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdarg.h>
7 #include <stdbool.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <sys/cdefs.h>
11
12 #include "esp_private/regdma_link.h"
13
14 #include "esp_heap_caps.h"
15 #include "esp_log.h"
16 #include "esp_regdma.h"
17
18
19
20 #define REGDMA_LINK_ADDR_ALIGN (4)
21 #define REGDMA_LINK_MEM_TYPE_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_DEFAULT)
22
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)23 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)
24 {
25 regdma_link_continuous_t *link = (regdma_link_continuous_t *)heap_caps_aligned_alloc(
26 REGDMA_LINK_ADDR_ALIGN,
27 buff ? sizeof(regdma_link_continuous_t) : (sizeof(regdma_link_continuous_t) + (len<<2)),
28 REGDMA_LINK_MEM_TYPE_CAPS
29 );
30 if (link) {
31 memset(link, 0, buff ? sizeof(regdma_link_continuous_t) : (sizeof(regdma_link_continuous_t) + (len<<2)));
32 void *buf = buff ? buff : (void *)(link->buff);
33 link = regdma_link_init_continuous(link, buf, backup, len, restore, next, skip_b, skip_r, id, module);
34 return (void *)((void *)link + offsetof(regdma_link_continuous_t, head));
35 }
36 return NULL;
37 }
38
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)39 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)
40 {
41 regdma_link_addr_map_t *link = (regdma_link_addr_map_t *)heap_caps_aligned_alloc(
42 REGDMA_LINK_ADDR_ALIGN,
43 buff ? sizeof(regdma_link_addr_map_t) : (sizeof(regdma_link_addr_map_t) + (len<<2)),
44 REGDMA_LINK_MEM_TYPE_CAPS
45 );
46 if (link) {
47 memset(link, 0, buff ? sizeof(regdma_link_addr_map_t) : (sizeof(regdma_link_addr_map_t) + (len<<2)));
48 void *buf = buff ? buff : (void *)(link->buff);
49 link = regdma_link_init_addr_map(link, buf, backup, bitmap, len, restore, next, skip_b, skip_r, id, module);
50 return (void *)((void *)link + offsetof(regdma_link_addr_map_t, head));
51 }
52 return NULL;
53 }
54
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)55 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)
56 {
57 regdma_link_write_wait_t *link = (regdma_link_write_wait_t *)heap_caps_aligned_alloc(
58 REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
59 if (link) {
60 memset(link, 0, sizeof(regdma_link_write_wait_t));
61 link = regdma_link_init_write(link, backup, value, mask, next, skip_b, skip_r, id, module);
62 return (void *)((void *)link + offsetof(regdma_link_write_wait_t, head));
63 }
64 return NULL;
65 }
66
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)67 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)
68 {
69 regdma_link_write_wait_t *link = (regdma_link_write_wait_t *)heap_caps_aligned_alloc(
70 REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
71 if (link) {
72 memset(link, 0, sizeof(regdma_link_write_wait_t));
73 link = regdma_link_init_wait(link, backup, value, mask, next, skip_b, skip_r, id, module);
74 return (void *)((void *)link + offsetof(regdma_link_write_wait_t, head));
75 }
76 return NULL;
77 }
78
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)79 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)
80 {
81 regdma_link_branch_continuous_t *link = (regdma_link_branch_continuous_t *)heap_caps_aligned_alloc(
82 REGDMA_LINK_ADDR_ALIGN,
83 buff ? sizeof(regdma_link_branch_continuous_t) : (sizeof(regdma_link_branch_continuous_t) + (len<<2)),
84 REGDMA_LINK_MEM_TYPE_CAPS
85 );
86 if (link) {
87 memset(link, 0, buff ? sizeof(regdma_link_branch_continuous_t) : (sizeof(regdma_link_branch_continuous_t) + (len<<2)));
88 void *buf = buff ? buff : (void *)(link->buff);
89 link = regdma_link_init_branch_continuous(link, buf, backup, len, restore, next, skip_b, skip_r, id, module);
90 return (void *)((void *)link + offsetof(regdma_link_branch_continuous_t, head));
91 }
92 return NULL;
93 }
94
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)95 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)
96 {
97 regdma_link_branch_addr_map_t *link = (regdma_link_branch_addr_map_t *)heap_caps_aligned_alloc(
98 REGDMA_LINK_ADDR_ALIGN,
99 buff ? sizeof(regdma_link_branch_addr_map_t) : (sizeof(regdma_link_branch_addr_map_t) + (len<<2)),
100 REGDMA_LINK_MEM_TYPE_CAPS
101 );
102 if (link) {
103 memset(link, 0, buff ? sizeof(regdma_link_branch_addr_map_t) : (sizeof(regdma_link_branch_addr_map_t) + (len<<2)));
104 void *buf = buff ? buff : (void *)(link->buff);
105 link = regdma_link_init_branch_addr_map(link, buf, backup, bitmap, len, restore, next, skip_b, skip_r, id, module);
106 return (void *)((void *)link + offsetof(regdma_link_branch_addr_map_t, head));
107 }
108 return NULL;
109 }
110
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)111 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)
112 {
113 regdma_link_branch_write_wait_t *link = (regdma_link_branch_write_wait_t *)heap_caps_aligned_alloc(
114 REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_branch_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
115 if (link) {
116 memset(link, 0, sizeof(regdma_link_branch_write_wait_t));
117 link = regdma_link_init_branch_write(link, backup, value, mask, next, skip_b, skip_r, id, module);
118 return (void *)((void *)link + offsetof(regdma_link_branch_write_wait_t, head));
119 }
120 return NULL;
121 }
122
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)123 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)
124 {
125 regdma_link_branch_write_wait_t *link = (regdma_link_branch_write_wait_t *)heap_caps_aligned_alloc(
126 REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_branch_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
127 if (link) {
128 memset(link, 0, sizeof(regdma_link_branch_write_wait_t));
129 link = regdma_link_init_branch_wait(link, backup, value, mask, next, skip_b, skip_r, id, module);
130 return (void *)((void *)link + offsetof(regdma_link_branch_write_wait_t, head));
131 }
132 return NULL;
133 }
134
regdma_link_new_continuous_default(void * backup,int len,void * restore,void * next,bool skip_b,bool skip_r,int id,uint32_t module)135 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)
136 {
137 return regdma_link_new_continuous(backup, NULL, len, restore, next, skip_b, skip_r, id, module);
138 }
139
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)140 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)
141 {
142 return regdma_link_new_addr_map(backup, NULL, bitmap, len, restore, next, skip_b, skip_r, id, module);
143 }
144
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)145 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)
146 {
147 return regdma_link_new_write(backup, value, mask, next, skip_b, skip_r, id, module);
148 }
149
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)150 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)
151 {
152 return regdma_link_new_wait(backup, value, mask, next, skip_b, skip_r, id, module);
153 }
154
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)155 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)
156 {
157 return regdma_link_new_branch_continuous(backup, NULL, len, restore, next, skip_b, skip_r, id, module);
158 }
159
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)160 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)
161 {
162 return regdma_link_new_branch_addr_map(backup, NULL, bitmap, len, restore, next, skip_b, skip_r, id, module);
163 }
164
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)165 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)
166 {
167 return regdma_link_new_branch_write(backup, value, mask, next, skip_b, skip_r, id, module);
168 }
169
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)170 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)
171 {
172 return regdma_link_new_branch_wait(backup, value, mask, next, skip_b, skip_r, id, module);
173 }
174
175
regdma_link_init_continuous_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)176 static void * regdma_link_init_continuous_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
177 {
178 regdma_entry_buf_t next;
179
180 memset(next, 0, sizeof(regdma_entry_buf_t));
181 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
182 next[i] = va_arg(args, void *);
183 }
184 return regdma_link_new_continuous_default((void *)(config->continuous.backup), config->head.length,
185 (void *)(config->continuous.restore), next[0], config->head.skip_b,
186 config->head.skip_r, config->id, module);
187 }
188
regdma_link_init_addr_map_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)189 static void * regdma_link_init_addr_map_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
190 {
191 regdma_entry_buf_t next;
192
193 memset(next, 0, sizeof(regdma_entry_buf_t));
194 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
195 next[i] = va_arg(args, void *);
196 }
197 return regdma_link_new_addr_map_default((void *)(config->addr_map.backup), (void *)(config->addr_map.map),
198 config->head.length, (void *)(config->addr_map.restore), next[0], config->head.skip_b,
199 config->head.skip_r, config->id, module);
200 }
201
regdma_link_init_write_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)202 static void * regdma_link_init_write_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
203 {
204 regdma_entry_buf_t next;
205
206 memset(next, 0, sizeof(regdma_entry_buf_t));
207 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
208 next[i] = va_arg(args, void *);
209 }
210 return regdma_link_new_write_default((void *)(config->write_wait.backup), config->write_wait.value,
211 config->write_wait.mask, next[0], config->head.skip_b, config->head.skip_r,
212 config->id, module);
213 }
214
regdma_link_init_wait_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)215 static void * regdma_link_init_wait_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
216 {
217 regdma_entry_buf_t next;
218
219 memset(next, 0, sizeof(regdma_entry_buf_t));
220 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
221 next[i] = va_arg(args, void *);
222 }
223 return regdma_link_new_wait_default((void *)(config->write_wait.backup), config->write_wait.value,
224 config->write_wait.mask, next[0], config->head.skip_b, config->head.skip_r,
225 config->id, module);
226 }
227
regdma_link_init_branch_continuous_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)228 static void * regdma_link_init_branch_continuous_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
229 {
230 regdma_entry_buf_t next;
231
232 memset(next, 0, sizeof(regdma_entry_buf_t));
233 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
234 next[i] = va_arg(args, void *);
235 }
236 return regdma_link_new_branch_continuous_default((void *)(config->continuous.backup),
237 config->head.length, (void *)(config->continuous.restore), &next,
238 config->head.skip_b, config->head.skip_r, config->id, module);
239 }
240
regdma_link_init_branch_addr_map_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)241 static void * regdma_link_init_branch_addr_map_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
242 {
243 regdma_entry_buf_t next;
244
245 memset(next, 0, sizeof(regdma_entry_buf_t));
246 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
247 next[i] = va_arg(args, void *);
248 }
249 return regdma_link_new_branch_addr_map_default((void *)(config->addr_map.backup),
250 (void *)(config->addr_map.map), config->head.length, (void *)(config->addr_map.restore),
251 &next, config->head.skip_b, config->head.skip_r, config->id, module);
252 }
253
regdma_link_init_branch_write_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)254 static void * regdma_link_init_branch_write_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
255 {
256 regdma_entry_buf_t next;
257
258 memset(next, 0, sizeof(regdma_entry_buf_t));
259 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
260 next[i] = va_arg(args, void *);
261 }
262 return regdma_link_new_branch_write_default((void *)(config->write_wait.backup),
263 config->write_wait.value, config->write_wait.mask, &next, config->head.skip_b,
264 config->head.skip_r, config->id, module);
265 }
266
regdma_link_init_branch_wait_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)267 static void * regdma_link_init_branch_wait_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
268 {
269 regdma_entry_buf_t next;
270
271 memset(next, 0, sizeof(regdma_entry_buf_t));
272 for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
273 next[i] = va_arg(args, void *);
274 }
275 return regdma_link_new_branch_wait_default((void *)(config->write_wait.backup),
276 config->write_wait.value, config->write_wait.mask, &next, config->head.skip_b,
277 config->head.skip_r, config->id, module);
278 }
279
regdma_link_init_wrapper(const regdma_link_config_t * config,bool branch,uint32_t module,int nentry,va_list args)280 static void * regdma_link_init_wrapper(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, va_list args)
281 {
282 typedef void * (*init_fn_t)(const void *, uint32_t, int, va_list);
283
284 const static init_fn_t initfn[] = {
285 [0] = (init_fn_t)regdma_link_init_continuous_wrapper, /* REGDMA_LINK_MODE_CONTINUOUS */
286 [1] = (init_fn_t)regdma_link_init_addr_map_wrapper, /* REGDMA_LINK_MODE_ADDR_MAP */
287 [2] = (init_fn_t)regdma_link_init_write_wrapper, /* REGDMA_LINK_MODE_WRITE */
288 [3] = (init_fn_t)regdma_link_init_wait_wrapper /* REGDMA_LINK_MODE_WAIT */
289 };
290 const static init_fn_t initfn_b[] = {
291 [0] = (init_fn_t)regdma_link_init_branch_continuous_wrapper,
292 [1] = (init_fn_t)regdma_link_init_branch_addr_map_wrapper,
293 [2] = (init_fn_t)regdma_link_init_branch_write_wrapper,
294 [3] = (init_fn_t)regdma_link_init_branch_wait_wrapper
295 };
296
297 assert((config->head.mode < ARRAY_SIZE(initfn)) && (config->head.mode < ARRAY_SIZE(initfn_b)));
298
299 init_fn_t pfn = branch ? initfn_b[config->head.mode] : initfn[config->head.mode];
300 return (*pfn)(config, module, nentry, args);
301 }
302
regdma_link_init(const regdma_link_config_t * config,bool branch,uint32_t module,int nentry,...)303 void * regdma_link_init(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, ...)
304 {
305 assert(config != NULL);
306
307 va_list args;
308 va_start(args, nentry);
309 void * link = regdma_link_init_wrapper(config, branch, module, nentry, args);
310 va_end(args);
311 return link;
312 }
313
regdma_link_get_next_continuous_wrapper(void * link)314 static void * regdma_link_get_next_continuous_wrapper(void *link)
315 {
316 regdma_link_continuous_t *continuous = __containerof(link, regdma_link_continuous_t, head);
317 return (void *)(continuous->body.next);
318 }
319
regdma_link_get_next_addr_map_wrapper(void * link)320 static void * regdma_link_get_next_addr_map_wrapper(void *link)
321 {
322 regdma_link_addr_map_t *addr_map = __containerof(link, regdma_link_addr_map_t, head);
323 return (void *)(addr_map->body.next);
324 }
325
regdma_link_get_next_write_wait_wrapper(void * link)326 static void * regdma_link_get_next_write_wait_wrapper(void *link)
327 {
328 regdma_link_write_wait_t *write_wait = __containerof(link, regdma_link_write_wait_t, head);
329 return (void *)(write_wait->body.next);
330 }
331
regdma_link_get_next_branch_continuous_wrapper(void * link)332 static regdma_entry_buf_t * regdma_link_get_next_branch_continuous_wrapper(void *link)
333 {
334 regdma_link_branch_continuous_t *branch_continuous = __containerof(link, regdma_link_branch_continuous_t, head);
335 return &branch_continuous->body.next;
336 }
337
regdma_link_get_next_branch_addr_map_wrapper(void * link)338 static regdma_entry_buf_t * regdma_link_get_next_branch_addr_map_wrapper(void *link)
339 {
340 regdma_link_branch_addr_map_t *branch_addr_map = __containerof(link, regdma_link_branch_addr_map_t, head);
341 return &branch_addr_map->body.next;
342 }
343
regdma_link_get_next_branch_write_wait_wrapper(void * link)344 static regdma_entry_buf_t * regdma_link_get_next_branch_write_wait_wrapper(void *link)
345 {
346 regdma_link_branch_write_wait_t *branch_write_wait = __containerof(link, regdma_link_branch_write_wait_t, head);
347 return &branch_write_wait->body.next;
348 }
349
regdma_link_get_next(void * link,int entry)350 static void * regdma_link_get_next(void *link, int entry)
351 {
352 if (link) {
353 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
354 if (head.branch) {
355 typedef regdma_entry_buf_t * (*get_nextfn1_t)(void *);
356 const static get_nextfn1_t nextfn1[] = {
357 [0] = (get_nextfn1_t)regdma_link_get_next_branch_continuous_wrapper,
358 [1] = (get_nextfn1_t)regdma_link_get_next_branch_addr_map_wrapper,
359 [2] = (get_nextfn1_t)regdma_link_get_next_branch_write_wait_wrapper,
360 [3] = (get_nextfn1_t)regdma_link_get_next_branch_write_wait_wrapper
361 };
362 assert(head.mode < ARRAY_SIZE(nextfn1));
363 regdma_entry_buf_t *next = (*nextfn1[head.mode])(link);
364 if ((entry < REGDMA_LINK_ENTRY_NUM) && (*next)[entry] && (head.eof == 0)) {
365 return (*next)[entry];
366 }
367 } else {
368 typedef void * (*get_nextfn0_t)(void *);
369 const static get_nextfn0_t nextfn0[] = {
370 [0] = (get_nextfn0_t)regdma_link_get_next_continuous_wrapper,
371 [1] = (get_nextfn0_t)regdma_link_get_next_addr_map_wrapper,
372 [2] = (get_nextfn0_t)regdma_link_get_next_write_wait_wrapper,
373 [3] = (get_nextfn0_t)regdma_link_get_next_write_wait_wrapper
374 };
375 assert(head.mode < ARRAY_SIZE(nextfn0));
376 void *next = (*nextfn0[head.mode])(link);
377 if (next && (head.eof == 0)) {
378 return next;
379 }
380 }
381 }
382 return NULL;
383 }
384
regdma_link_recursive_impl(void * link,int entry,int depth,void (* hook)(void *,int,int))385 static void * regdma_link_recursive_impl(void *link, int entry, int depth, void (*hook)(void *, int, int))
386 {
387 assert(entry < REGDMA_LINK_ENTRY_NUM);
388
389 if (link) {
390 regdma_link_recursive_impl(regdma_link_get_next(link, entry), entry, depth+1, hook);
391 if (hook) {
392 (*hook)(link, entry, depth);
393 }
394 }
395 return link;
396 }
397
regdma_link_recursive(void * link,int entry,void (* hook)(void *,int,int))398 void * regdma_link_recursive(void *link, int entry, void (*hook)(void *, int, int))
399 {
400 return regdma_link_recursive_impl(link, entry, 0, hook);
401 }
402
regdma_link_get_instance(void * link)403 static void * regdma_link_get_instance(void *link)
404 {
405 void * container_memaddr[] = {
406 (void *)__containerof(link, regdma_link_continuous_t, head),
407 (void *)__containerof(link, regdma_link_addr_map_t, head),
408 (void *)__containerof(link, regdma_link_write_wait_t, head),
409 (void *)__containerof(link, regdma_link_write_wait_t, head),
410 (void *)__containerof(link, regdma_link_branch_continuous_t, head),
411 (void *)__containerof(link, regdma_link_branch_addr_map_t, head),
412 (void *)__containerof(link, regdma_link_branch_write_wait_t, head),
413 (void *)__containerof(link, regdma_link_branch_write_wait_t, head)
414 };
415 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
416 int it = (head.branch << 2) | head.mode;
417 assert(it < ARRAY_SIZE(container_memaddr));
418
419 return container_memaddr[it];
420 }
regdma_link_get_stats(void * link)421 static regdma_link_stats_t * regdma_link_get_stats(void *link)
422 {
423 const static size_t stats_offset[] = {
424 offsetof(regdma_link_continuous_t, stat),
425 offsetof(regdma_link_addr_map_t, stat),
426 offsetof(regdma_link_write_wait_t, stat),
427 offsetof(regdma_link_write_wait_t, stat),
428 offsetof(regdma_link_branch_continuous_t, stat),
429 offsetof(regdma_link_branch_addr_map_t, stat),
430 offsetof(regdma_link_branch_write_wait_t, stat),
431 offsetof(regdma_link_branch_write_wait_t, stat)
432 };
433 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
434 int it = (head.branch << 2) | head.mode;
435 assert(it < ARRAY_SIZE(stats_offset));
436
437 return (regdma_link_stats_t *)(regdma_link_get_instance(link) + stats_offset[it]);
438 }
439
regdma_link_update_stats_wrapper(void * link,int entry,int depth)440 static void regdma_link_update_stats_wrapper(void *link, int entry, int depth)
441 {
442 if (link == NULL) {
443 return;
444 }
445 regdma_link_update_stats(regdma_link_get_stats(link), entry, depth);
446 }
447
regdma_link_stats(void * link,int entry)448 void regdma_link_stats(void *link, int entry)
449 {
450 regdma_link_recursive_impl(link, entry, 0, regdma_link_update_stats_wrapper);
451 }
452
regdma_link_destroy_wrapper(void * link,int entry,int depth)453 static void regdma_link_destroy_wrapper(void *link, int entry, int depth)
454 {
455 if (link == NULL) {
456 return;
457 }
458 regdma_link_stats_t *stat = regdma_link_get_stats(link);
459 stat->ref &= ~BIT(entry);
460 if (stat->ref == 0) {
461 free(regdma_link_get_instance(link));
462 }
463 }
464
regdma_link_destroy(void * link,int entry)465 void regdma_link_destroy(void *link, int entry)
466 {
467 regdma_link_recursive_impl(link, entry, 0, regdma_link_destroy_wrapper);
468 }
469
regdma_find_link_by_pos(void * link,int entry,int pos)470 void * regdma_find_link_by_pos(void *link, int entry, int pos)
471 {
472 assert(entry < REGDMA_LINK_ENTRY_NUM);
473
474 void *next = link;
475 if (link) {
476 int iter = 0;
477 do {
478 if (pos == iter++) {
479 break;
480 }
481 } while ((next = regdma_link_get_next(next, entry)) != NULL);
482 }
483 return next;
484 }
485
regdma_find_link_by_id(void * link,int entry,int id)486 void * regdma_find_link_by_id(void *link, int entry, int id)
487 {
488 assert(entry < REGDMA_LINK_ENTRY_NUM);
489
490 void *find_addr = NULL;
491 void *next = link;
492 if (link) {
493 int linkid = 0;
494 do {
495 regdma_link_head_t head = REGDMA_LINK_HEAD(next);
496 if (head.branch) {
497 regdma_link_branch_continuous_t *continuous = (regdma_link_branch_continuous_t *)regdma_link_get_instance(next);
498 linkid = continuous->stat.id;
499 } else {
500 regdma_link_continuous_t *continuous = (regdma_link_continuous_t *)regdma_link_get_instance(next);
501 linkid = continuous->stat.id;
502 }
503 if (linkid == id) {
504 find_addr = next;
505 break;
506 }
507 } while ((next = regdma_link_get_next(next, entry)) != NULL);
508 }
509 return find_addr;
510 }
511
regdma_link_set_write_wait_content(void * link,uint32_t value,uint32_t mask)512 void regdma_link_set_write_wait_content(void *link, uint32_t value, uint32_t mask)
513 {
514 if (link) {
515 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
516 if (head.mode == REGDMA_LINK_MODE_WRITE || head.mode == REGDMA_LINK_MODE_WAIT) {
517 if (head.branch) {
518 regdma_link_branch_write_wait_t *write_wait = (regdma_link_branch_write_wait_t *)regdma_link_get_instance(link);
519 write_wait->body.value = value;
520 write_wait->body.mask = mask;
521 } else {
522 regdma_link_write_wait_t *write_wait = (regdma_link_write_wait_t *)regdma_link_get_instance(link);
523 write_wait->body.value = value;
524 write_wait->body.mask = mask;
525 }
526 }
527 }
528 }
529
regdma_link_update_continuous_next_wrapper(void * link,void * next)530 static void regdma_link_update_continuous_next_wrapper(void *link, void *next)
531 {
532 regdma_link_continuous_t *continuous = __containerof(link, regdma_link_continuous_t, head);
533 continuous->body.next = next;
534 }
535
regdma_link_update_addr_map_next_wrapper(void * link,void * next)536 static void regdma_link_update_addr_map_next_wrapper(void *link, void *next)
537 {
538 regdma_link_addr_map_t *addr_map = __containerof(link, regdma_link_addr_map_t, head);
539 addr_map->body.next = next;
540 }
541
regdma_link_update_write_wait_next_wrapper(void * link,void * next)542 static void regdma_link_update_write_wait_next_wrapper(void *link, void *next)
543 {
544 regdma_link_write_wait_t *write_wait = __containerof(link, regdma_link_write_wait_t, head);
545 write_wait->body.next = next;
546 }
547
regdma_link_update_branch_continuous_next_wrapper(void * link,regdma_entry_buf_t * next)548 static void regdma_link_update_branch_continuous_next_wrapper(void *link, regdma_entry_buf_t *next)
549 {
550 regdma_link_branch_continuous_t *branch_continuous = __containerof(link, regdma_link_branch_continuous_t, head);
551 for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
552 branch_continuous->body.next[i] = (*next)[i];
553 }
554 }
555
regdma_link_update_branch_addr_map_next_wrapper(void * link,regdma_entry_buf_t * next)556 static void regdma_link_update_branch_addr_map_next_wrapper(void *link, regdma_entry_buf_t *next)
557 {
558 regdma_link_branch_addr_map_t *branch_addr_map = __containerof(link, regdma_link_branch_addr_map_t, head);
559 for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
560 branch_addr_map->body.next[i] = (*next)[i];
561 }
562 }
563
regdma_link_update_branch_write_wait_next_wrapper(void * link,regdma_entry_buf_t * next)564 static void regdma_link_update_branch_write_wait_next_wrapper(void *link, regdma_entry_buf_t *next)
565 {
566 regdma_link_branch_write_wait_t *branch_write_wait = __containerof(link, regdma_link_branch_write_wait_t, head);
567 for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
568 branch_write_wait->body.next[i] = (*next)[i];
569 }
570 }
571
regdma_link_update_next(void * link,int nentry,...)572 void regdma_link_update_next(void *link, int nentry, ...)
573 {
574 va_list args;
575 va_start(args, nentry);
576 if (link) {
577 regdma_entry_buf_t next;
578 memset(next, 0, sizeof(regdma_entry_buf_t));
579 for (int i = 0; i < nentry && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
580 next[i] = va_arg(args, void *);
581 }
582
583 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
584 if (head.branch) {
585 typedef void (*update_branch_fn_t)(void *, regdma_entry_buf_t *);
586 static const update_branch_fn_t updatefn_b[] = {
587 [0] = regdma_link_update_branch_continuous_next_wrapper,
588 [1] = regdma_link_update_branch_addr_map_next_wrapper,
589 [2] = regdma_link_update_branch_write_wait_next_wrapper,
590 [3] = regdma_link_update_branch_write_wait_next_wrapper
591 };
592 assert((head.mode < ARRAY_SIZE(updatefn_b)));
593 (*updatefn_b[head.mode])(link, &next);
594 } else {
595 typedef void (*update_fn_t)(void *, void *);
596 static const update_fn_t updatefn[] = {
597 [0] = regdma_link_update_continuous_next_wrapper,
598 [1] = regdma_link_update_addr_map_next_wrapper,
599 [2] = regdma_link_update_write_wait_next_wrapper,
600 [3] = regdma_link_update_write_wait_next_wrapper
601 };
602 assert((head.mode < ARRAY_SIZE(updatefn)));
603 (*updatefn[head.mode])(link, next[0]);
604 }
605 }
606 va_end(args);
607 }
608
regdma_link_get_owner_bitmap(void * link,void * tail,int entry)609 uint32_t regdma_link_get_owner_bitmap(void *link, void *tail, int entry)
610 {
611 assert(entry < REGDMA_LINK_ENTRY_NUM);
612
613 uint32_t owner = 0;
614 void *next = link;
615 if (link) {
616 do {
617 owner |= regdma_link_get_stats(next)->ref;
618 if (next == tail) {
619 break;
620 }
621 } while ((next = regdma_link_get_next(next, entry)) != NULL);
622 }
623 return owner;
624 }
625
regdma_find_module_link_head(void * link,void * tail,int entry,uint32_t module)626 void * regdma_find_module_link_head(void *link, void *tail, int entry, uint32_t module)
627 {
628 assert(entry < REGDMA_LINK_ENTRY_NUM);
629
630 void *find_link = NULL;
631 void *next = link;
632 if (link) {
633 do {
634 if (regdma_link_get_stats(next)->module & module) {
635 find_link = next;
636 break;
637 }
638 if (next == tail) {
639 break;
640 }
641 } while ((next = regdma_link_get_next(next, entry)) != NULL);
642 }
643 return find_link;
644 }
645
regdma_find_module_link_tail(void * link,void * tail,int entry,uint32_t module)646 void * regdma_find_module_link_tail(void *link, void *tail, int entry, uint32_t module)
647 {
648 assert(entry < REGDMA_LINK_ENTRY_NUM);
649
650 void *find_tail = NULL;
651 void *next = link;
652 if (link) {
653 do {
654 if (next != tail) {
655 void *temp = regdma_link_get_next(next, entry);
656 if ((regdma_link_get_stats(next)->module & module) &&
657 !(regdma_link_get_stats(temp)->module & module)) {
658 find_tail = next;
659 break;
660 }
661 } else {
662 if (regdma_link_get_stats(next)->module & module) {
663 find_tail = next;
664 break;
665 }
666 }
667 } while ((next = regdma_link_get_next(next, entry)) != NULL);
668 }
669 return find_tail;
670 }
671
regdma_find_next_module_link_head(void * link,void * tail,int entry,uint32_t module)672 void * regdma_find_next_module_link_head(void *link, void *tail, int entry, uint32_t module)
673 {
674 assert(entry < REGDMA_LINK_ENTRY_NUM);
675 void *find_tail = regdma_find_module_link_tail(link, tail, entry, module);
676 if (find_tail && find_tail != tail) {
677 return regdma_link_get_next(find_tail, entry);
678 }
679 return NULL;
680 }
681
regdma_find_prev_module_link_tail(void * link,void * tail,int entry,uint32_t module)682 void * regdma_find_prev_module_link_tail(void *link, void *tail, int entry, uint32_t module)
683 {
684 assert(entry < REGDMA_LINK_ENTRY_NUM);
685 void *find_head = regdma_find_module_link_head(link, tail, entry, module);
686 void *next = link;
687 if (find_head && find_head != link) {
688 do {
689 if (regdma_link_get_next(next, entry) == find_head) {
690 return next;
691 }
692 if (next == tail) {
693 break;
694 }
695 } while ((next = regdma_link_get_next(next, entry)) != NULL);
696 }
697 return NULL;
698 }
699
700 #if REGDMA_LINK_DBG
701 static const char *TAG = "regdma_link";
702
print_info_continuous_wrapper(void * link)703 static void print_info_continuous_wrapper(void *link)
704 {
705 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
706 regdma_link_continuous_t *cons = __containerof(link, regdma_link_continuous_t, head);
707 ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:%x, backup:%x, restore:%x, buff:%x",
708 cons->stat.module, cons->stat.id, link, cons->head, cons->body.next,
709 cons->body.backup, cons->body.restore, cons->body.mem);
710 ESP_LOG_BUFFER_HEX(TAG, (const void *)cons->body.mem, head.length);
711 }
712
print_info_addr_map_wrapper(void * link)713 static void print_info_addr_map_wrapper(void *link)
714 {
715 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
716 regdma_link_addr_map_t *map = __containerof(link, regdma_link_addr_map_t, head);
717 ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:%x, backup:%x, restore:%x, buff:%x, map:{%x,%x,%x,%x}",
718 map->stat.module, map->stat.id, link, map->head, map->body.next, map->body.backup,
719 map->body.restore, map->body.mem, map->body.map[0], map->body.map[1],
720 map->body.map[2], map->body.map[3]);
721 ESP_LOG_BUFFER_HEX(TAG, (const void *)map->body.mem, head.length);
722 }
723
print_info_write_wait_wrapper(void * link)724 static void print_info_write_wait_wrapper(void *link)
725 {
726 regdma_link_write_wait_t *ww = __containerof(link, regdma_link_write_wait_t, head);
727 ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:%x, backup:%x, value:%x, mask:%x",
728 ww->stat.module, ww->stat.id, link, ww->head, ww->body.next,
729 ww->body.backup, ww->body.value, ww->body.mask);
730 }
731
print_info_branch_continuous_wrapper(void * link)732 static void print_info_branch_continuous_wrapper(void *link)
733 {
734 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
735 regdma_link_branch_continuous_t *cons = __containerof(link, regdma_link_branch_continuous_t, head);
736 ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:{%x,%x,%x,%x}, backup:%x, restore:%x, buff:%x",
737 cons->stat.module, cons->stat.id, link, cons->head, cons->body.next[0], cons->body.next[1],
738 cons->body.next[2], cons->body.next[3], cons->body.backup, cons->body.restore,
739 cons->body.mem);
740 ESP_LOG_BUFFER_HEX(TAG, (const void *)cons->body.mem, head.length);
741 }
742
print_info_branch_addr_map_wrapper(void * link)743 static void print_info_branch_addr_map_wrapper(void *link)
744 {
745 regdma_link_head_t head = REGDMA_LINK_HEAD(link);
746 regdma_link_branch_addr_map_t *map = __containerof(link, regdma_link_branch_addr_map_t, head);
747 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}",
748 map->stat.module, map->stat.id, link, map->head, map->body.next[0], map->body.next[1], map->body.next[2],
749 map->body.next[3], map->body.backup, map->body.restore, map->body.mem, map->body.map[0],
750 map->body.map[1], map->body.map[2], map->body.map[3]);
751 ESP_LOG_BUFFER_HEX(TAG, (const void *)map->body.mem, head.length);
752 }
753
print_info_branch_write_wait_wrapper(void * link)754 static void print_info_branch_write_wait_wrapper(void *link)
755 {
756 regdma_link_branch_write_wait_t *ww = __containerof(link, regdma_link_branch_write_wait_t, head);
757 ESP_EARLY_LOGI(TAG, "[%08x/%04x] link:%x, head:%x, next:{%x,%x,%x,%x}, backup:%x, value:%x, mask:%x",
758 ww->stat.module, ww->stat.id, link, ww->head, ww->body.next[0], ww->body.next[1],
759 ww->body.next[2], ww->body.next[3], ww->body.backup, ww->body.value,
760 ww->body.mask);
761 }
762
print_link_info(void * args,int entry,int depth)763 static void print_link_info(void *args, int entry, int depth)
764 {
765 typedef void (*prinf_fn_t)(void *);
766
767 const static prinf_fn_t prinf_fn[] = {
768 [0] = (prinf_fn_t)print_info_continuous_wrapper,
769 [1] = (prinf_fn_t)print_info_addr_map_wrapper,
770 [2] = (prinf_fn_t)print_info_write_wait_wrapper,
771 [3] = (prinf_fn_t)print_info_write_wait_wrapper,
772 [4] = (prinf_fn_t)print_info_branch_continuous_wrapper,
773 [5] = (prinf_fn_t)print_info_branch_addr_map_wrapper,
774 [6] = (prinf_fn_t)print_info_branch_write_wait_wrapper,
775 [7] = (prinf_fn_t)print_info_branch_write_wait_wrapper
776 };
777
778 regdma_link_head_t head = REGDMA_LINK_HEAD(args);
779 int it = (head.branch << 2) | head.mode;
780 assert(it < ARRAY_SIZE(prinf_fn));
781
782 (*prinf_fn[it])(args);
783 }
784
regdma_link_show_memories(void * link,int entry)785 void regdma_link_show_memories(void *link, int entry)
786 {
787 assert(entry < REGDMA_LINK_ENTRY_NUM);
788
789 void *next = link;
790 if (link) {
791 do {
792 print_link_info(next, entry, 0);
793 } while ((next = regdma_link_get_next(next, entry)) != NULL);
794 } else {
795 ESP_EARLY_LOGW(TAG, "This REGDMA linked list is empty!\n");
796 }
797 }
798 #endif
799