1 /***************************************************************************//**
2 * \file cyhal_dma.c
3 *
4 * \brief
5 * Implements a high level interface for interacting with the Infineon DMA.
6 * This implementation abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2018-2021 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 * http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29
30 #include "cyhal_dma.h"
31 #include "cyhal_system.h"
32 #include "cyhal_hwmgr.h"
33
34 #if (CYHAL_DRIVER_AVAILABLE_DMA)
35
36 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
37 #include "cyhal_dma_dmac.h"
38 #endif
39 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
40 #include "cyhal_dma_dw.h"
41 #endif
42
43 #if defined(__cplusplus)
44 extern "C" {
45 #endif /* __cplusplus */
46
47
cyhal_dma_init_adv(cyhal_dma_t * obj,cyhal_dma_src_t * src,cyhal_dma_dest_t * dest,cyhal_source_t * dest_source,uint8_t priority,cyhal_dma_direction_t direction)48 cy_rslt_t cyhal_dma_init_adv(
49 cyhal_dma_t *obj, cyhal_dma_src_t *src, cyhal_dma_dest_t *dest, cyhal_source_t *dest_source, uint8_t priority, cyhal_dma_direction_t direction)
50 {
51 CY_ASSERT(NULL != obj);
52
53 obj->direction = direction;
54 obj->callback_data.callback = NULL;
55 obj->callback_data.callback_arg = NULL;
56 obj->irq_cause = 0;
57 obj->source = CYHAL_TRIGGER_CPUSS_ZERO;
58 obj->owned_by_configurator = false;
59
60 cy_rslt_t rslt;
61 cyhal_source_t *src_trigger = (NULL == src) ? NULL : &src->source;
62 cyhal_dest_t *dest_trigger = (NULL == dest) ? NULL : &dest->dest;
63
64 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW && !_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
65 /* Only DW available. */
66 rslt = _cyhal_dma_dw_init(obj, src_trigger, dest_trigger, priority);
67 #elif (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC && !_CYHAL_DRIVER_AVAILABLE_DMA_DW)
68 /* Only DMAC available. */
69 rslt = _cyhal_dma_dmac_init(obj, src_trigger, dest_trigger, priority);
70 #else
71 /* DMAC is designed with high memory bandwidth for memory to memory
72 * transfers so prefer it when direction is MEM2MEM. Otherwise prefer
73 * Datawire as it is designed for low latency memory to peripheral or
74 * peripheral to memory transfers. Note: Both DMA types can handle any
75 * direction value so using a non-ideal DMA type is ok.*/
76 if(direction == CYHAL_DMA_DIRECTION_MEM2MEM)
77 {
78 rslt = _cyhal_dma_dmac_init(obj, src_trigger, dest_trigger, priority);
79 /* If no DMAC channels are available fall back on DW. */
80 if(CYHAL_HWMGR_RSLT_ERR_NONE_FREE == rslt)
81 rslt = _cyhal_dma_dw_init(obj, src_trigger, dest_trigger, priority);
82 }
83 else
84 {
85 rslt = _cyhal_dma_dw_init(obj, src_trigger, dest_trigger, priority);
86 /* If no DW channels are available fall back on DMAC. */
87 if(CYHAL_HWMGR_RSLT_ERR_NONE_FREE == rslt)
88 rslt = _cyhal_dma_dmac_init(obj, src_trigger, dest_trigger, priority);
89 }
90 #endif
91
92 if (CY_RSLT_SUCCESS == rslt)
93 {
94 if (NULL != src)
95 {
96 rslt = cyhal_dma_connect_digital(obj, src->source, src->input);
97 obj->source = src->source;
98 }
99
100 if ((CY_RSLT_SUCCESS == rslt) && (NULL != dest))
101 {
102 rslt = cyhal_dma_enable_output(obj, dest->output, dest_source);
103 }
104
105 // If connection setup failed, free the resources.
106 if (CY_RSLT_SUCCESS != rslt)
107 {
108 cyhal_dma_free(obj);
109 }
110 }
111
112 return rslt;
113 }
114
cyhal_dma_init_cfg(cyhal_dma_t * obj,const cyhal_dma_configurator_t * cfg)115 cy_rslt_t cyhal_dma_init_cfg(cyhal_dma_t *obj, const cyhal_dma_configurator_t *cfg)
116 {
117 CY_ASSERT(NULL != obj);
118 CY_ASSERT(NULL != cfg);
119
120 obj->owned_by_configurator = true;
121
122 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
123 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
124 if (cfg->resource->type == CYHAL_RSC_DMA)
125 #endif
126 {
127 return _cyhal_dma_dmac_init_cfg(obj, cfg);
128 }
129 #endif
130 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
131 CY_ASSERT(cfg->resource->type == CYHAL_RSC_DW);
132 return _cyhal_dma_dw_init_cfg(obj, cfg);
133 #endif
134 }
135
cyhal_dma_free(cyhal_dma_t * obj)136 void cyhal_dma_free(cyhal_dma_t *obj)
137 {
138 CY_ASSERT(NULL != obj);
139 CY_ASSERT(!cyhal_dma_is_busy(obj));
140
141 cy_rslt_t rslt;
142 // DMA signal enum values don't matter since they are actually the same connection
143 rslt = cyhal_dma_disable_output(obj, CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS);
144 CY_ASSERT(CY_RSLT_SUCCESS == rslt);
145 if (CYHAL_TRIGGER_CPUSS_ZERO != obj->source)
146 {
147 rslt = cyhal_dma_disconnect_digital(obj, obj->source, CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS);
148 CY_ASSERT(CY_RSLT_SUCCESS == rslt);
149 }
150 (void)rslt; // Disable compiler warning in release build
151
152 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
153 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
154 if(obj->resource.type == CYHAL_RSC_DMA)
155 #endif
156 {
157 _cyhal_dma_dmac_free(obj);
158 }
159 #endif
160 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
161 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
162 if(obj->resource.type == CYHAL_RSC_DW)
163 #endif
164 {
165 _cyhal_dma_dw_free(obj);
166 }
167 #endif
168
169 if (!obj->owned_by_configurator)
170 {
171 cyhal_hwmgr_free(&obj->resource);
172 }
173 }
174
cyhal_dma_configure(cyhal_dma_t * obj,const cyhal_dma_cfg_t * cfg)175 cy_rslt_t cyhal_dma_configure(cyhal_dma_t *obj, const cyhal_dma_cfg_t *cfg)
176 {
177 CY_ASSERT(NULL != obj);
178
179 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
180 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
181 if(obj->resource.type == CYHAL_RSC_DMA)
182 #endif
183 {
184 return _cyhal_dma_dmac_configure(obj, cfg);
185 }
186 #endif
187 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
188 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
189 return _cyhal_dma_dw_configure(obj, cfg);
190 #endif
191 }
192
cyhal_dma_start_transfer(cyhal_dma_t * obj)193 cy_rslt_t cyhal_dma_start_transfer(cyhal_dma_t *obj)
194 {
195 CY_ASSERT(NULL != obj);
196
197 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
198 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
199 if(obj->resource.type == CYHAL_RSC_DMA)
200 #endif
201 {
202 return _cyhal_dma_dmac_start_transfer(obj);
203 }
204 #endif
205 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
206 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
207 return _cyhal_dma_dw_start_transfer(obj);
208 #endif
209 }
210
cyhal_dma_enable(cyhal_dma_t * obj)211 cy_rslt_t cyhal_dma_enable(cyhal_dma_t *obj)
212 {
213 CY_ASSERT(NULL != obj);
214
215 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
216 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
217 if(obj->resource.type == CYHAL_RSC_DMA)
218 #endif
219 {
220 return _cyhal_dma_dmac_enable(obj);
221 }
222 #endif
223 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
224 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
225 return _cyhal_dma_dw_enable(obj);
226 #endif
227 }
228
cyhal_dma_disable(cyhal_dma_t * obj)229 cy_rslt_t cyhal_dma_disable(cyhal_dma_t *obj)
230 {
231 CY_ASSERT(NULL != obj);
232
233 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
234 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
235 if(obj->resource.type == CYHAL_RSC_DMA)
236 #endif
237 {
238 return _cyhal_dma_dmac_disable(obj);
239 }
240 #endif
241 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
242 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
243 return _cyhal_dma_dw_disable(obj);
244 #endif
245 }
246
cyhal_dma_is_busy(cyhal_dma_t * obj)247 bool cyhal_dma_is_busy(cyhal_dma_t *obj)
248 {
249 CY_ASSERT(NULL != obj);
250
251 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
252 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
253 if(obj->resource.type == CYHAL_RSC_DMA)
254 #endif
255 {
256 return _cyhal_dma_dmac_is_busy(obj);
257 }
258 #endif
259 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
260 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
261 return _cyhal_dma_dw_is_busy(obj);
262 #endif
263 }
264
cyhal_dma_register_callback(cyhal_dma_t * obj,cyhal_dma_event_callback_t callback,void * callback_arg)265 void cyhal_dma_register_callback(cyhal_dma_t *obj, cyhal_dma_event_callback_t callback, void *callback_arg)
266 {
267 CY_ASSERT(NULL != obj);
268
269 uint32_t saved_intr_status = cyhal_system_critical_section_enter();
270 obj->callback_data.callback = (cy_israddress)callback;
271 obj->callback_data.callback_arg = callback_arg;
272 cyhal_system_critical_section_exit(saved_intr_status);
273 }
274
cyhal_dma_enable_event(cyhal_dma_t * obj,cyhal_dma_event_t event,uint8_t intr_priority,bool enable)275 void cyhal_dma_enable_event(cyhal_dma_t *obj, cyhal_dma_event_t event, uint8_t intr_priority, bool enable)
276 {
277 CY_ASSERT(NULL != obj);
278
279 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
280 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
281 if(obj->resource.type == CYHAL_RSC_DMA)
282 #endif
283 {
284 _cyhal_dma_dmac_enable_event(obj, event, intr_priority, enable);
285 return;
286 }
287 #endif
288 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
289 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
290 _cyhal_dma_dw_enable_event(obj, event, intr_priority, enable);
291 #endif
292 }
293
cyhal_dma_connect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)294 cy_rslt_t cyhal_dma_connect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
295 {
296 CY_ASSERT(NULL != obj);
297
298 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
299 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
300 if(obj->resource.type == CYHAL_RSC_DMA)
301 #endif
302 {
303 return _cyhal_dma_dmac_connect_digital(obj, source, input);
304 }
305 #endif
306 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
307 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
308 return _cyhal_dma_dw_connect_digital(obj, source, input);
309 #endif
310 }
311
cyhal_dma_enable_output(cyhal_dma_t * obj,cyhal_dma_output_t output,cyhal_source_t * source)312 cy_rslt_t cyhal_dma_enable_output(cyhal_dma_t *obj, cyhal_dma_output_t output, cyhal_source_t *source)
313 {
314 CY_ASSERT(NULL != obj);
315
316 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
317 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
318 if(obj->resource.type == CYHAL_RSC_DMA)
319 #endif
320 {
321 return _cyhal_dma_dmac_enable_output(obj, output, source);
322 }
323 #endif
324 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
325 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
326 return _cyhal_dma_dw_enable_output(obj, output, source);
327 #endif
328 }
329
cyhal_dma_disconnect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)330 cy_rslt_t cyhal_dma_disconnect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
331 {
332 CY_ASSERT(NULL != obj);
333
334 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
335 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
336 if(obj->resource.type == CYHAL_RSC_DMA)
337 #endif
338 {
339 return _cyhal_dma_dmac_disconnect_digital(obj, source, input);
340 }
341 #endif
342 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
343 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
344 return _cyhal_dma_dw_disconnect_digital(obj, source, input);
345 #endif
346 }
347
cyhal_dma_disable_output(cyhal_dma_t * obj,cyhal_dma_output_t output)348 cy_rslt_t cyhal_dma_disable_output(cyhal_dma_t *obj, cyhal_dma_output_t output)
349 {
350 CY_ASSERT(NULL != obj);
351
352 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
353 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
354 if(obj->resource.type == CYHAL_RSC_DMA)
355 #endif
356 {
357 return _cyhal_dma_dmac_disable_output(obj, output);
358 }
359 #endif
360 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DW)
361 CY_ASSERT(obj->resource.type == CYHAL_RSC_DW);
362 return _cyhal_dma_dw_disable_output(obj, output);
363 #endif
364 }
365
366 #if defined(__cplusplus)
367 }
368 #endif /* __cplusplus */
369
370 #endif /* (CYHAL_DRIVER_AVAILABLE_DMA) */
371