1 /***************************************************************************//**
2 * \file cyhal_dma_dmac.c
3 *
4 * \brief
5 * Implements a high level interface for interacting with the Infineon DMAC.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2021 Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 *     http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 *******************************************************************************/
26 
27 #include "cyhal_dma.h"
28 #include "cyhal_dma_dmac.h"
29 #include "cyhal_dma_impl.h"
30 #include "cyhal_hwmgr_impl.h"
31 #include "cyhal_interconnect.h"
32 #include "cyhal_syspm.h"
33 #include "cyhal_utils.h"
34 #include "cyhal_triggers.h"
35 
36 #if defined(__cplusplus)
37 extern "C" {
38 #endif
39 
40 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
41 
42 #if defined(CY_IP_M4CPUSS_DMAC)
43 #define DMAC0_IRQn                  (cpuss_interrupts_dmac_0_IRQn)
44 #define GET_RESOURCE_DATA(x)        (x.dmac)
45 typedef DMAC_Type                   cyhal_dmac_hw_type;
46 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
47 #define DMAC0_IRQn                  (cpuss_interrupt_dma_IRQn)
48 #define GET_RESOURCE_DATA(x)        (x)
49 #define CY_TRIGGER_TWO_CYCLES       (2)
50 typedef DMAC_Type                   cyhal_dmac_hw_type;
51 #elif defined(CY_IP_MXAHBDMAC)
52 #define DMAC0_IRQn                  (cpuss_interrupts_dmac0_0_IRQn)
53 #define DMAC1_IRQn                  (cpuss_interrupts_dmac1_0_IRQn)
54 #define GET_RESOURCE_DATA(x)        (x.dmac)
55 typedef MXAHBDMAC_Type              cyhal_dmac_hw_type;
56 #endif
57 
58 #if defined(CPUSS_DMAC0_CH_NR) && defined(CPUSS_DMAC1_CH_NR)
59 #define NUM_DMAC_CHANNELS           (CPUSS_DMAC0_CH_NR + CPUSS_DMAC1_CH_NR)
60 #elif defined(CPUSS_DMAC_CH_NR)
61 #define NUM_DMAC_CHANNELS           (CPUSS_DMAC_CH_NR)
62 #define CPUSS_DMAC0_CH_NR           (CPUSS_DMAC_CH_NR)
63 #define CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0   (CYHAL_TRIGGER_CPUSS_DMAC_TR_IN0)
64 #define _CYHAL_TRIGGER_CPUSS_DMAC0_TR_OUT0 (_CYHAL_TRIGGER_CPUSS_DMAC_TR_OUT0)
65 #endif
66 
67 
68 
69 static cyhal_dma_t* _cyhal_dma_dmac_config_structs[NUM_DMAC_CHANNELS];
70 
71 /** Default dmac descriptor config */
72 static const cy_stc_dmac_descriptor_config_t _cyhal_dma_dmac_default_descriptor_config =
73 {
74     .srcAddress = 0,                                // Overriden by cyhal_dma_cfg_t.src_addr
75     .dstAddress = 0,                                // Overriden by cyhal_dma_cfg_t.dst_addr
76     .dataSize = CY_DMAC_WORD,                       // Overridden by cyhal_dma_cfg_t.transfer_width
77     .dstTransferSize = CY_DMAC_TRANSFER_SIZE_DATA,  // Overriden by direction
78     .srcTransferSize = CY_DMAC_TRANSFER_SIZE_DATA,  // Overriden by direction
79     .retrigger = CY_DMAC_RETRIG_IM,
80 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
81     .interruptType = CY_DMAC_DESCR,                 // Overridden by cyhal_dma_cfg_t.action
82     .triggerOutType = CY_DMAC_DESCR_CHAIN,          // Overridden by [en/dis]able_output()
83     .channelState = CY_DMAC_CHANNEL_ENABLED,
84     .triggerInType = CY_DMAC_DESCR,                 // Overridden by cyhal_dma_cfg_t.action & [dis]connect_digital()
85     .dataPrefetch = false,
86     .descriptorType = CY_DMAC_1D_TRANSFER,          // Overriden by cyhal_dma_cfg_t.burst_size
87     .srcXincrement = 1U,                            // Overriden by cyhal_dma_cfg_t.src_increment
88     .dstXincrement = 1U,                            // Overriden by cyhal_dma_cfg_t.dst_increment
89     .xCount = 1UL,                                  // Overriden by cyhal_dma_cfg_t.length/burst_size
90     .srcYincrement = 0U,                            // Overriden by cyhal_dma_cfg_t.burst_size
91     .dstYincrement = 0U,                            // Overriden by cyhal_dma_cfg_t.burst_size
92     .yCount = 1UL,                                  // Overriden by cyhal_dma_cfg_t.length
93     .nextDescriptor = 0,
94 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
95     .triggerType = CY_DMAC_SINGLE_DESCR,
96     .dataCount = 1,                                 // Overriden by cyhal_dma_cfg_t.length
97     .dstAddrIncrement = true,                       // Overriden by cyhal_dma_cfg_t.dst_increment
98     .srcAddrIncrement = true,                       // Overriden by cyhal_dma_cfg_t.src_increment
99     .interrupt = true,
100     .preemptable = true,
101     .flipping = false,
102 #endif
103 };
104 
105 /** Default dmac channel config */
106 static const cy_stc_dmac_channel_config_t _cyhal_dma_dmac_default_channel_config =
107 {
108     .priority = 1,                          // Overriden by config().priority
109     .enable = false,
110 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
111     .bufferable = false,
112     .descriptor = 0,                        // Overriden by config()
113 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
114     .descriptor = CY_DMAC_DESCRIPTOR_PING,  // Overriden by config()
115 #endif
116 };
117 
118 static bool _cyhal_dma_dmac_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg);
119 
120 static cyhal_syspm_callback_data_t _cyhal_dma_dmac_pm_callback_args = {
121     .callback = &_cyhal_dma_dmac_pm_callback,
122     .states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE),
123     .next = NULL,
124     .args = NULL,
125     .ignore_modes = CYHAL_SYSPM_BEFORE_TRANSITION,
126 };
127 static bool _cyhal_dma_dmac_pm_transition_pending = false;
_cyhal_dma_dmac_has_enabled(void)128 static bool _cyhal_dma_dmac_has_enabled(void)
129 {
130     for (uint8_t i = 0; i < NUM_DMAC_CHANNELS; i++)
131         if (_cyhal_dma_dmac_config_structs[i])
132             return true;
133     return false;
134 }
135 
_cyhal_dma_dmac_pm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)136 static bool _cyhal_dma_dmac_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg)
137 {
138     CY_UNUSED_PARAMETER(state);
139     CY_UNUSED_PARAMETER(callback_arg);
140     bool block_transition = false;
141     switch(mode)
142     {
143         case CYHAL_SYSPM_CHECK_READY:
144             for (uint8_t i = 0; (i < NUM_DMAC_CHANNELS) && !block_transition; i++)
145             {
146                 block_transition |= (_cyhal_dma_dmac_config_structs[i] != NULL) && _cyhal_dma_dmac_is_busy(_cyhal_dma_dmac_config_structs[i]);
147             }
148             _cyhal_dma_dmac_pm_transition_pending = !block_transition;
149             break;
150         case CYHAL_SYSPM_CHECK_FAIL:
151         case CYHAL_SYSPM_AFTER_TRANSITION:
152             _cyhal_dma_dmac_pm_transition_pending = false;
153             break;
154         default:
155             CY_ASSERT(false);
156             break;
157     }
158     return _cyhal_dma_dmac_pm_transition_pending;
159 }
160 
161 /** Gets the dmac configuration struct offset */
_cyhal_dma_dmac_get_cfg_offset(const cyhal_dma_t * obj)162 static inline uint8_t _cyhal_dma_dmac_get_cfg_offset(const cyhal_dma_t* obj)
163 {
164     return (obj->resource.block_num * CPUSS_DMAC0_CH_NR) + obj->resource.channel_num;
165 }
166 
167 /** Sets the dmac configuration struct */
_cyhal_dma_dmac_set_obj(cyhal_dma_t * obj)168 static inline void _cyhal_dma_dmac_set_obj(cyhal_dma_t *obj)
169 {
170     _cyhal_dma_dmac_config_structs[_cyhal_dma_dmac_get_cfg_offset(obj)] = obj;
171 }
172 
173 /** Zeros the dmac configuration struct */
_cyhal_dma_dmac_free_obj(cyhal_dma_t * obj)174 static inline void _cyhal_dma_dmac_free_obj(cyhal_dma_t *obj)
175 {
176     _cyhal_dma_dmac_config_structs[_cyhal_dma_dmac_get_cfg_offset(obj)] = NULL;
177 }
178 
179 /** Gets the dmac configuration struct from block and channel */
_cyhal_dma_dmac_get_obj(uint8_t block,uint8_t channel)180 static inline cyhal_dma_t* _cyhal_dma_dmac_get_obj(uint8_t block, uint8_t channel)
181 {
182     return _cyhal_dma_dmac_config_structs[(block * CPUSS_DMAC0_CH_NR) + channel];
183 }
184 
185 /** Gets the dmac block number from irq number */
186 /** This should never be called from a non-dma IRQn */
_cyhal_dma_dmac_get_block_from_irqn(IRQn_Type irqn)187 static inline uint8_t _cyhal_dma_dmac_get_block_from_irqn(IRQn_Type irqn)
188 {
189     uint8_t diff = irqn - DMAC0_IRQn;
190 #if defined(CPUSS_DMAC0_CH_NR) && !defined(CPUSS_DMAC1_CH_NR)
191     CY_ASSERT(diff < CPUSS_DMAC0_CH_NR);
192 
193     if (diff < CPUSS_DMAC0_CH_NR)
194         return 0;
195 #elif defined(CPUSS_DMAC0_CH_NR) && defined(CPUSS_DMAC1_CH_NR)
196     CY_ASSERT(diff < CPUSS_DMAC0_CH_NR + CPUSS_DMAC1_CH_NR);
197 
198     if (diff < CPUSS_DMAC0_CH_NR)
199         return 0;
200     if (diff < CPUSS_DMAC0_CH_NR + CPUSS_DMAC1_CH_NR)
201         return 1;
202 #endif
203 
204     // Should never reach here. Just silencing compiler warnings.
205     CY_ASSERT(false);
206     return 0xFF;
207 }
208 
209 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
210 /** Gets the dmac channel number from irq number */
211 /** This should never be called from a non-dma IRQn */
_cyhal_dma_dmac_get_channel_from_irqn(IRQn_Type irqn)212 static inline uint8_t _cyhal_dma_dmac_get_channel_from_irqn(IRQn_Type irqn)
213 {
214     uint8_t diff = irqn - DMAC0_IRQn;
215 #if defined(CPUSS_DMAC0_CH_NR) && !defined(CPUSS_DMAC1_CH_NR)
216     CY_ASSERT(diff < CPUSS_DMAC0_CH_NR);
217 
218     if (diff < CPUSS_DMAC0_CH_NR)
219         return diff;
220 #elif defined(CPUSS_DMAC0_CH_NR) && defined(CPUSS_DMAC1_CH_NR)
221     CY_ASSERT(diff < CPUSS_DMAC0_CH_NR + CPUSS_DW1_CH_NR);
222 
223     if (diff < CPUSS_DMAC0_CH_NR)
224         return diff;
225     else
226         return diff - CPUSS_DMAC0_CH_NR;
227 #endif
228 
229     // Should never reach here. Just silencing compiler warnings.
230     CY_ASSERT(false);
231     return 0xFF;
232 }
233 #endif
234 
235 /** Gets the irqn corresponding to a particular cyhal_dma_t config struct */
_cyhal_dma_dmac_get_irqn(cyhal_dma_t * obj)236 static inline IRQn_Type _cyhal_dma_dmac_get_irqn(cyhal_dma_t *obj)
237 {
238     #if defined(CY_IP_M0S8CPUSSV3_DMAC)
239         CY_UNUSED_PARAMETER(obj);
240         /* This IP has a single ganged IRQ for all DMA channels */
241         return DMAC0_IRQn;
242     #else
243         return (IRQn_Type)((uint8_t)DMAC0_IRQn + _cyhal_dma_dmac_get_cfg_offset(obj));
244     #endif
245 }
246 
247 /** Gets the dmac base pointer from block number */
_cyhal_dma_dmac_get_base(uint8_t block_num)248 static inline cyhal_dmac_hw_type* _cyhal_dma_dmac_get_base(uint8_t block_num)
249 {
250 #if defined(CPUSS_DMAC0_CH_NR) && !defined(CPUSS_DMAC1_CH_NR)
251     CY_UNUSED_PARAMETER(block_num);
252     return DMAC;
253 #elif defined(CPUSS_DMAC0_CH_NR) && defined(CPUSS_DMAC1_CH_NR)
254     return (block_num == 0) ? MXAHBDMAC0 : MXAHBDMAC1;
255 #endif
256 }
257 
258 /** Uses tables provided as part of the hal interconnect driver to determine mux
259  * trigger group and mux trigger index and then construct the trigger line
260  * input parameter to Cy_TrigMux_SwTrigger. */
_cyhal_dma_dmac_get_trigger_line(uint8_t block_num,uint8_t channel_num)261 static inline uint32_t _cyhal_dma_dmac_get_trigger_line(uint8_t block_num, uint8_t channel_num)
262 {
263     /* cyhal_dest_t triggers are guaranteed to be sorted by trigger type, block
264      * num, then channel num, therefore, we can just directly find the proper
265      * trigger by calculating an offset. */
266     cyhal_dest_t trigger = (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + (block_num * CPUSS_DMAC0_CH_NR) + channel_num);
267 
268     /* One to one triggers have bit 8 set in cyhal_dest_to_mux but
269      * Cy_TrigMux_SwTrigger wants the trigger group field to have bit 5 set to
270      * denote one to one triggers. */
271     uint8_t trig_group = cyhal_dest_to_mux[trigger];
272     /* If hal one to one triggers bit is set: mask it out and set pdl one to
273      * one bit */
274     if(trig_group & _CYHAL_DMA_TRIGGERS_1TO1_MASK)
275         trig_group = (trig_group & ~_CYHAL_DMA_TRIGGERS_1TO1_MASK) | _CYHAL_DMA_PDL_TRIGGERS_1TO1_MASK;
276 
277     /* Construct trigger line which consists of three fields packed into a
278      * uint32_t:
279      * Bits   30: Input/output bit. Set to 1 for output.
280      * Bits 12-8: Trigger group selection.
281      * Bits  7-0: Select the output trigger number in the trigger group. */
282 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
283     return PERI_TR_CMD_OUT_SEL_Msk | ((uint32_t)trig_group << 8) | cyhal_mux_dest_index[trigger];
284 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
285     return PERI_TR_CTL_TR_OUT_Msk | ((uint32_t)trig_group << 8) | cyhal_mux_dest_index[trigger];
286 #endif
287 }
288 
289 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
290 /** Convert PDL interrupt cause to hal dma event */
_cyhal_dma_dmac_convert_interrupt_cause(cyhal_dma_t * obj,uint32_t cause)291 static inline cyhal_dma_event_t _cyhal_dma_dmac_convert_interrupt_cause(cyhal_dma_t *obj, uint32_t cause)
292 {
293     static const cyhal_dma_event_t hal[] =
294     {
295         CYHAL_DMA_TRANSFER_COMPLETE,
296         CYHAL_DMA_SRC_BUS_ERROR,
297         CYHAL_DMA_DST_BUS_ERROR,
298         CYHAL_DMA_SRC_MISAL,
299         CYHAL_DMA_DST_MISAL,
300         CYHAL_DMA_CURR_PTR_NULL,
301         CYHAL_DMA_ACTIVE_CH_DISABLED,
302         CYHAL_DMA_DESCR_BUS_ERROR
303     };
304 
305     cyhal_dma_event_t hal_rslt = CYHAL_DMA_NO_INTR;
306     for (uint8_t i = 0; cause > 0 && i < sizeof(hal)/sizeof(cyhal_dma_event_t); i++)
307     {
308         if ((cause & (1 << i)) > 0)
309         hal_rslt |= hal[i];
310     }
311 
312     if ((uint32_t)(hal_rslt & CYHAL_DMA_TRANSFER_COMPLETE) > 0 && obj->expected_bursts > 0)
313     {
314         obj->expected_bursts--;
315         if (0 == obj->expected_bursts)
316         {
317             hal_rslt |= CYHAL_DMA_DESCRIPTOR_COMPLETE;
318 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
319             obj->expected_bursts = (GET_RESOURCE_DATA(obj->descriptor_config).interruptType == CY_DMAC_X_LOOP)
320                 ? GET_RESOURCE_DATA(obj->descriptor_config).yCount
321                 : 1;
322 #else
323             obj->expected_bursts = 1;
324 #endif
325         }
326     }
327 
328     return hal_rslt;
329 }
330 #endif
331 
332 /** DMAC irq handler */
_cyhal_dma_dmac_irq_handler(void)333 static void _cyhal_dma_dmac_irq_handler(void)
334 {
335     /* Use irqn to get appropriate config structure */
336     uint8_t block = _cyhal_dma_dmac_get_block_from_irqn(_CYHAL_UTILS_GET_CURRENT_IRQN());
337     DMAC_Type* base = _cyhal_dma_dmac_get_base(block);
338 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
339     uint8_t channel = _cyhal_dma_dmac_get_channel_from_irqn(_CYHAL_UTILS_GET_CURRENT_IRQN());
340     cyhal_dma_t *obj = _cyhal_dma_dmac_get_obj(block, channel);
341 
342     /* Get interrupt type and call users event callback if they have enabled that event */
343     uint32_t cause = Cy_DMAC_Channel_GetInterruptStatusMasked(base, channel);
344     cyhal_dma_event_t event_type = _cyhal_dma_dmac_convert_interrupt_cause(obj, cause);
345     uint32_t events_to_callback = event_type & obj->irq_cause;
346     if(obj->callback_data.callback != NULL && events_to_callback)
347     {
348         ((cyhal_dma_event_callback_t)obj->callback_data.callback)(obj->callback_data.callback_arg, (cyhal_dma_event_t)events_to_callback);
349     }
350 
351     /* Clear all interrupts */
352     Cy_DMAC_Channel_ClearInterrupt(base, channel, CY_DMAC_INTR_MASK);
353 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
354     uint32_t channels = Cy_DMAC_GetInterruptStatusMasked(base);
355     for(int i = 0 ; ((uint32_t)(1 << i)) <= channels ; i++)
356     {
357         cyhal_dma_t *obj = _cyhal_dma_dmac_get_obj(block, i);
358         if (obj != NULL)
359         {
360             if (((channels & (1 << i)) != 0) && (obj->callback_data.callback != NULL))
361             {
362                 ((cyhal_dma_event_callback_t)obj->callback_data.callback)(obj->callback_data.callback_arg, CYHAL_DMA_TRANSFER_COMPLETE);
363             }
364         }
365     }
366     Cy_DMAC_ClearInterrupt(_cyhal_dma_dmac_get_base(block), channels);
367 #endif
368 }
369 
_cyhal_dma_dmac_get_src(uint8_t block_num,uint8_t channel_num)370 static cyhal_source_t _cyhal_dma_dmac_get_src(uint8_t block_num, uint8_t channel_num)
371 {
372     return (cyhal_source_t)_CYHAL_TRIGGER_CREATE_SOURCE((_CYHAL_TRIGGER_CPUSS_DMAC0_TR_OUT0 + (block_num * CPUSS_DMAC0_CH_NR) + channel_num), CYHAL_SIGNAL_TYPE_EDGE);
373 }
374 
_cyhal_dma_dmac_get_dest(uint8_t block_num,uint8_t channel_num)375 static cyhal_dest_t _cyhal_dma_dmac_get_dest(uint8_t block_num, uint8_t channel_num)
376 {
377     return (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + (block_num * CPUSS_DMAC0_CH_NR) + channel_num);
378 }
379 
_cyhal_dma_dmac_stage(cyhal_dma_t * obj)380 static cy_rslt_t _cyhal_dma_dmac_stage(cyhal_dma_t *obj)
381 {
382     cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
383 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
384     cy_rslt_t rslt = Cy_DMAC_Descriptor_Init(GET_RESOURCE_DATA(&obj->descriptor), GET_RESOURCE_DATA(&obj->descriptor_config));
385 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
386     cy_rslt_t rslt = Cy_DMAC_Descriptor_Init(base, obj->resource.channel_num, obj->descriptor, GET_RESOURCE_DATA(&obj->descriptor_config));
387 #endif
388     if(CY_DMAC_SUCCESS != rslt)
389         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
390 
391     /* Setup channel and enable */
392     if(CY_DMAC_SUCCESS != Cy_DMAC_Channel_Init(base, obj->resource.channel_num, GET_RESOURCE_DATA(&obj->channel_config)))
393         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
394 
395 
396 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
397     Cy_DMAC_Channel_SetInterruptMask(base, obj->resource.channel_num, CY_DMAC_INTR_MASK);
398 #endif
399 
400     Cy_DMAC_Enable(base);
401 
402 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
403     /* src_misal and dst_misal interrupts are triggered immediately on enable
404      * so return those errors here */
405     uint32_t status = Cy_DMAC_Channel_GetInterruptStatus(base, obj->resource.channel_num);
406     if((status & CY_DMAC_INTR_SRC_MISAL) ||
407        (status & CY_DMAC_INTR_DST_MISAL))
408     {
409         /* Clear all interrupts and return error */
410         Cy_DMAC_Channel_ClearInterrupt(base, obj->resource.channel_num, CY_DMAC_INTR_MASK);
411         return CYHAL_DMA_RSLT_ERR_INVALID_ALIGNMENT;
412     }
413 #endif
414 
415     /* Enable interrupt for this channel; preserve user priority if they enabled an interrupt */
416     IRQn_Type irqn = _cyhal_dma_dmac_get_irqn(obj);
417     uint32_t priority = (CYHAL_DMA_NO_INTR == obj->irq_cause)
418         ? CYHAL_ISR_PRIORITY_DEFAULT
419         : NVIC_GetPriority(irqn);
420 
421     cy_stc_sysint_t irqCfg = { irqn, priority };
422     if(CY_SYSINT_SUCCESS != Cy_SysInt_Init(&irqCfg, _cyhal_dma_dmac_irq_handler))
423         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
424     NVIC_EnableIRQ(irqCfg.intrSrc);
425 
426     return CY_RSLT_SUCCESS;
427 }
428 
_cyhal_dma_dmac_init(cyhal_dma_t * obj,cyhal_source_t * src,cyhal_dest_t * dest,uint8_t priority)429 cy_rslt_t _cyhal_dma_dmac_init(cyhal_dma_t *obj, cyhal_source_t *src, cyhal_dest_t *dest, uint8_t priority)
430 {
431     if(!CY_DMAC_IS_PRIORITY_VALID(priority))
432         return CYHAL_DMA_RSLT_ERR_INVALID_PRIORITY;
433 
434     if (_cyhal_dma_dmac_pm_transition_pending)
435     {
436         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
437     }
438 
439     cy_rslt_t rslt = _cyhal_hwmgr_allocate_with_connection(
440         CYHAL_RSC_DMA, src, dest, _cyhal_dma_dmac_get_src, _cyhal_dma_dmac_get_dest, &obj->resource);
441     if(rslt != CY_RSLT_SUCCESS)
442         return rslt;
443 
444     obj->callback_data.callback = NULL;
445 
446     /* Setup descriptor and channel configs */
447     GET_RESOURCE_DATA(obj->descriptor_config) = _cyhal_dma_dmac_default_descriptor_config;
448     GET_RESOURCE_DATA(obj->channel_config) = _cyhal_dma_dmac_default_channel_config;
449 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
450     GET_RESOURCE_DATA(obj->channel_config).descriptor = GET_RESOURCE_DATA(&obj->descriptor);
451 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
452     obj->descriptor = obj->channel_config.descriptor;
453 #endif
454     GET_RESOURCE_DATA(obj->channel_config).priority = priority;
455 
456     if (!_cyhal_dma_dmac_has_enabled())
457     {
458         _cyhal_syspm_register_peripheral_callback(&_cyhal_dma_dmac_pm_callback_args);
459     }
460 
461     _cyhal_dma_dmac_set_obj(obj);
462 
463     return CY_RSLT_SUCCESS;
464 }
465 
_cyhal_dma_dmac_init_cfg(cyhal_dma_t * obj,const cyhal_dma_configurator_t * cfg)466 cy_rslt_t _cyhal_dma_dmac_init_cfg(cyhal_dma_t *obj, const cyhal_dma_configurator_t *cfg)
467 {
468     if (_cyhal_dma_dmac_pm_transition_pending)
469     {
470         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
471     }
472 
473     obj->resource = *(cfg->resource);
474     obj->callback_data.callback = NULL;
475 
476     /* Setup descriptor and channel configs */
477 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
478     obj->descriptor_config.dmac = *(cfg->dmac_descriptor_config);
479     obj->channel_config.dmac = *(cfg->dmac_channel_config);
480     GET_RESOURCE_DATA(obj->channel_config).descriptor = GET_RESOURCE_DATA(&obj->descriptor);
481     obj->expected_bursts = cfg->dmac_descriptor_config->yCount;
482 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
483     obj->descriptor_config = *(cfg->descriptor_config);
484     obj->channel_config = *(cfg->channel_config);
485     obj->descriptor = obj->channel_config.descriptor;
486     obj->expected_bursts = 1;
487 #endif
488 
489     if (!_cyhal_dma_dmac_has_enabled())
490     {
491         _cyhal_syspm_register_peripheral_callback(&_cyhal_dma_dmac_pm_callback_args);
492     }
493 
494     _cyhal_dma_dmac_set_obj(obj);
495 
496     return _cyhal_dma_dmac_stage(obj);
497 }
498 
_cyhal_dma_dmac_free(cyhal_dma_t * obj)499 void _cyhal_dma_dmac_free(cyhal_dma_t *obj)
500 {
501     cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
502 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
503     Cy_DMAC_Descriptor_DeInit(GET_RESOURCE_DATA(&obj->descriptor));
504 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
505     Cy_DMAC_Descriptor_DeInit(base, obj->resource.channel_num, obj->descriptor);
506 #endif
507 
508     Cy_DMAC_Channel_DeInit(base, obj->resource.channel_num);
509 
510     NVIC_DisableIRQ(_cyhal_dma_dmac_get_irqn(obj));
511 
512     _cyhal_dma_dmac_free_obj(obj);
513 
514     if (!_cyhal_dma_dmac_has_enabled())
515     {
516         _cyhal_syspm_unregister_peripheral_callback(&_cyhal_dma_dmac_pm_callback_args);
517         _cyhal_dma_dmac_pm_transition_pending = false;
518     }
519 }
520 
521 /* Initialize descriptor, initialize channel, enable channel, enable channel
522  * interrupt, and enable DMAC controller */
_cyhal_dma_dmac_configure(cyhal_dma_t * obj,const cyhal_dma_cfg_t * cfg)523 cy_rslt_t _cyhal_dma_dmac_configure(cyhal_dma_t *obj, const cyhal_dma_cfg_t *cfg)
524 {
525     /* Do not reconfigure if transfer is pending/active already */
526     if(_cyhal_dma_dmac_is_busy(obj))
527         return CYHAL_DMA_RSLT_ERR_CHANNEL_BUSY;
528 
529     // DMAC only supports <=65536 byte burst and <=65536 bytes per burst
530     if ((cfg->burst_size > 65536) ||
531         ((cfg->burst_size <= 1) && (cfg->length > 65536)) ||
532         ((cfg->burst_size > 0) && (cfg->length > (cfg->burst_size * 65536))))
533         return CYHAL_DMA_RSLT_ERR_INVALID_TRANSFER_SIZE;
534 
535 #if defined(CY_IP_M0S8CPUSSV3_DMAC)
536     // PSoC™ 4 devices do not support automatically disabling the channel on completion
537     if ((cfg->action == CYHAL_DMA_TRANSFER_BURST_DISABLE) ||
538         (cfg->action == CYHAL_DMA_TRANSFER_FULL_DISABLE))
539     {
540         return CYHAL_DMA_RSLT_FATAL_UNSUPPORTED_HARDWARE;
541     }
542 #endif
543 
544     GET_RESOURCE_DATA(obj->descriptor_config).srcAddress = (void*)cfg->src_addr;
545     GET_RESOURCE_DATA(obj->descriptor_config).dstAddress = (void*)cfg->dst_addr;
546 
547     if(cfg->transfer_width == 8)
548         GET_RESOURCE_DATA(obj->descriptor_config).dataSize = CY_DMAC_BYTE;
549     else if(cfg->transfer_width == 16)
550         GET_RESOURCE_DATA(obj->descriptor_config).dataSize = CY_DMAC_HALFWORD;
551     else if(cfg->transfer_width == 32)
552         GET_RESOURCE_DATA(obj->descriptor_config).dataSize = CY_DMAC_WORD;
553     else
554         return CYHAL_DMA_RSLT_ERR_INVALID_TRANSFER_WIDTH;
555 
556     /* By default, transfer what the user set for dataSize. However, if transfering between memory
557      * and a peripheral, make sure the peripheral access is using words. */
558     GET_RESOURCE_DATA(obj->descriptor_config).srcTransferSize =
559         GET_RESOURCE_DATA(obj->descriptor_config).dstTransferSize = CY_DMAC_TRANSFER_SIZE_DATA;
560     if (obj->direction == CYHAL_DMA_DIRECTION_PERIPH2MEM)
561         GET_RESOURCE_DATA(obj->descriptor_config).srcTransferSize = CY_DMAC_TRANSFER_SIZE_WORD;
562     else if (obj->direction == CYHAL_DMA_DIRECTION_MEM2PERIPH)
563         GET_RESOURCE_DATA(obj->descriptor_config).dstTransferSize = CY_DMAC_TRANSFER_SIZE_WORD;
564 
565 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
566     GET_RESOURCE_DATA(obj->descriptor_config).nextDescriptor = GET_RESOURCE_DATA(&obj->descriptor);
567     if ((cfg->action == CYHAL_DMA_TRANSFER_BURST) || (cfg->action == CYHAL_DMA_TRANSFER_FULL))
568     {
569         GET_RESOURCE_DATA(obj->descriptor_config).channelState = CY_DMAC_CHANNEL_ENABLED;
570     }
571     else
572     {
573         GET_RESOURCE_DATA(obj->descriptor_config).channelState = CY_DMAC_CHANNEL_DISABLED;
574     }
575 
576     GET_RESOURCE_DATA(obj->descriptor_config).srcXincrement = cfg->src_increment;
577     GET_RESOURCE_DATA(obj->descriptor_config).dstXincrement = cfg->dst_increment;
578 
579     /* Setup 2D transfer if burst_size is being used otherwise set up 1D
580      * transfer */
581     if(cfg->burst_size != 0)
582     {
583         /* Length must be a multiple of burst_size */
584         if(cfg->length % cfg->burst_size != 0)
585             return CYHAL_DMA_RSLT_ERR_INVALID_BURST_SIZE;
586 
587         GET_RESOURCE_DATA(obj->descriptor_config).descriptorType = CY_DMAC_2D_TRANSFER;
588         GET_RESOURCE_DATA(obj->descriptor_config).xCount = cfg->burst_size;
589         GET_RESOURCE_DATA(obj->descriptor_config).yCount = cfg->length / cfg->burst_size;
590         GET_RESOURCE_DATA(obj->descriptor_config).srcYincrement = cfg->src_increment * cfg->burst_size;
591         GET_RESOURCE_DATA(obj->descriptor_config).dstYincrement = cfg->dst_increment * cfg->burst_size;
592     }
593     else
594     {
595         GET_RESOURCE_DATA(obj->descriptor_config).descriptorType = CY_DMAC_1D_TRANSFER;
596         GET_RESOURCE_DATA(obj->descriptor_config).xCount = cfg->length;
597     }
598 
599     /* If burst action, configure trigger and interrupt actions */
600     if (cfg->burst_size != 0 &&
601         (cfg->action == CYHAL_DMA_TRANSFER_BURST || cfg->action == CYHAL_DMA_TRANSFER_BURST_DISABLE))
602     {
603         obj->expected_bursts = GET_RESOURCE_DATA(obj->descriptor_config).yCount;
604         GET_RESOURCE_DATA(obj->descriptor_config).interruptType = CY_DMAC_X_LOOP;
605         if (obj->source == CYHAL_TRIGGER_CPUSS_ZERO) // If not overridden by connect_digital()
606             GET_RESOURCE_DATA(obj->descriptor_config).triggerInType = CY_DMAC_X_LOOP;
607     }
608     else
609     {
610         obj->expected_bursts = 1;
611         GET_RESOURCE_DATA(obj->descriptor_config).interruptType = CY_DMAC_DESCR;
612         if (obj->source == CYHAL_TRIGGER_CPUSS_ZERO) // If not overridden by connect_digital()
613             GET_RESOURCE_DATA(obj->descriptor_config).triggerInType = CY_DMAC_DESCR;
614      }
615 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
616     if(cfg->burst_size != 0)
617     {
618         return CYHAL_DMA_RSLT_ERR_INVALID_BURST_SIZE;
619     }
620     else
621     {
622         GET_RESOURCE_DATA(obj->descriptor_config).dataCount = cfg->length;
623         GET_RESOURCE_DATA(obj->descriptor_config).srcAddrIncrement = cfg->src_increment;
624         GET_RESOURCE_DATA(obj->descriptor_config).dstAddrIncrement = cfg->dst_increment;
625         obj->expected_bursts = 1;
626     }
627 #endif
628 
629     return _cyhal_dma_dmac_stage(obj);
630 }
631 
_cyhal_dma_dmac_enable(cyhal_dma_t * obj)632 cy_rslt_t _cyhal_dma_dmac_enable(cyhal_dma_t *obj)
633 {
634     cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
635     Cy_DMAC_Channel_Enable(base, obj->resource.channel_num);
636     return CY_RSLT_SUCCESS;
637 }
638 
_cyhal_dma_dmac_disable(cyhal_dma_t * obj)639 cy_rslt_t _cyhal_dma_dmac_disable(cyhal_dma_t *obj)
640 {
641     cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
642     Cy_DMAC_Channel_Disable(base, obj->resource.channel_num);
643     return CY_RSLT_SUCCESS;
644 }
645 
_cyhal_dma_dmac_start_transfer(cyhal_dma_t * obj)646 cy_rslt_t _cyhal_dma_dmac_start_transfer(cyhal_dma_t *obj)
647 {
648     /* Return warning if channel is busy */
649     if(_cyhal_dma_dmac_is_busy(obj))
650         return CYHAL_DMA_RSLT_WARN_TRANSFER_ALREADY_STARTED;
651 
652     if (_cyhal_dma_dmac_pm_transition_pending)
653         return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
654 
655     uint32_t trigline = _cyhal_dma_dmac_get_trigger_line(obj->resource.block_num, obj->resource.channel_num);
656     cy_en_trigmux_status_t trig_status = Cy_TrigMux_SwTrigger(trigline, CY_TRIGGER_TWO_CYCLES);
657 
658     /* Also return warning if SW trigger is already initiated but DMA hardware
659      * has not seen it yet */
660     if(trig_status == CY_TRIGMUX_INVALID_STATE)
661         return CYHAL_DMA_RSLT_WARN_TRANSFER_ALREADY_STARTED;
662     else
663         return CY_RSLT_SUCCESS;
664 }
665 
_cyhal_dma_dmac_enable_event(cyhal_dma_t * obj,cyhal_dma_event_t event,uint8_t intr_priority,bool enable)666 void _cyhal_dma_dmac_enable_event(cyhal_dma_t *obj, cyhal_dma_event_t event, uint8_t intr_priority, bool enable)
667 {
668 #if defined (CY_IP_M0S8CPUSSV3_DMAC)
669     DMAC_Type *base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
670     uint32_t mask = Cy_DMAC_GetInterruptMask(base);
671 #endif
672     if(enable)
673     {
674 #if defined (CY_IP_M0S8CPUSSV3_DMAC)
675         Cy_DMAC_SetInterruptMask(base, mask | (1 << obj->resource.channel_num));
676 #endif
677         obj->irq_cause |= event;
678     }
679     else
680     {
681 #if defined (CY_IP_M0S8CPUSSV3_DMAC)
682         Cy_DMAC_SetInterruptMask(base, mask & ~(1 << obj->resource.channel_num));
683 #endif
684         obj->irq_cause &= ~event;
685     }
686 
687     NVIC_SetPriority(_cyhal_dma_dmac_get_irqn(obj), intr_priority);
688 }
689 
_cyhal_dma_dmac_is_busy(cyhal_dma_t * obj)690 bool _cyhal_dma_dmac_is_busy(cyhal_dma_t *obj)
691 {
692     /* The value is a bit field of all pending or active channels */
693     return Cy_DMAC_GetActiveChannel(_cyhal_dma_dmac_get_base(obj->resource.block_num)) & (1 << obj->resource.channel_num);
694 }
695 
696 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
_cyhal_convert_input_t(cyhal_dma_input_t input)697 static cy_en_dmac_trigger_type_t _cyhal_convert_input_t(cyhal_dma_input_t input)
698 {
699     switch(input)
700     {
701         case CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT:
702             return CY_DMAC_1ELEMENT;
703         case CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST:
704             return CY_DMAC_X_LOOP;
705         case CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS:
706             return CY_DMAC_DESCR;
707         default:
708             // Should never reach here. Just silencing compiler warnings.
709             CY_ASSERT(false);
710             return CY_DMAC_DESCR;
711     }
712 }
713 
_cyhal_convert_output_t(cyhal_dma_output_t output)714 static cy_en_dmac_trigger_type_t _cyhal_convert_output_t(cyhal_dma_output_t output)
715 {
716     switch(output)
717     {
718         case CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT:
719             return CY_DMAC_1ELEMENT;
720         case CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST:
721             return CY_DMAC_X_LOOP;
722         case CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS:
723             return CY_DMAC_DESCR;
724         default:
725             // Should never reach here. Just silencing compiler warnings.
726             CY_ASSERT(false);
727             return CY_DMAC_DESCR;
728     }
729 }
730 
_cyhal_dma_dmac_connect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)731 cy_rslt_t _cyhal_dma_dmac_connect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
732 {
733     if(input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT &&
734        input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST &&
735        input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS)
736         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
737 
738     obj->descriptor_config.dmac.triggerInType = _cyhal_convert_input_t(input);
739     Cy_DMAC_Channel_Disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
740     obj->descriptor.dmac.ctl &= ~DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE_Msk;
741     obj->descriptor.dmac.ctl |= _VAL2FLD(DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE, obj->descriptor_config.dmac.triggerInType);
742     Cy_DMAC_Channel_Enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
743 
744     cyhal_dest_t dest = _cyhal_dma_dmac_get_dest(obj->resource.block_num, obj->resource.channel_num);
745 
746     return _cyhal_connect_signal(source, dest);
747 }
748 
_cyhal_dma_dmac_enable_output(cyhal_dma_t * obj,cyhal_dma_output_t output,cyhal_source_t * source)749 cy_rslt_t _cyhal_dma_dmac_enable_output(cyhal_dma_t *obj, cyhal_dma_output_t output, cyhal_source_t *source)
750 {
751     if(output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT &&
752        output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST &&
753        output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS)
754         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
755 
756     Cy_DMAC_Channel_Disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
757     obj->descriptor.dmac.ctl &= ~DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE_Msk;
758     obj->descriptor.dmac.ctl |= _VAL2FLD(DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE, _cyhal_convert_output_t(output));
759     Cy_DMAC_Channel_Enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
760 
761     *source = _cyhal_dma_dmac_get_src(obj->resource.block_num, obj->resource.channel_num);
762 
763     return CY_RSLT_SUCCESS;
764 }
765 
_cyhal_dma_dmac_disconnect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)766 cy_rslt_t _cyhal_dma_dmac_disconnect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
767 {
768     if(input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT &&
769        input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST &&
770        input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS)
771         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
772 
773     Cy_DMAC_Channel_Disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
774 
775     // There is no option to totally disable. Just reset to default.
776     // NOTE: Use .interruptType since it matches the desired .triggerInType from configure(), but
777     // is not modified by connect/disconnect functions
778     obj->descriptor.dmac.ctl &= ~DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE_Msk;
779     obj->descriptor.dmac.ctl |= _VAL2FLD(DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE, _cyhal_dma_dmac_default_descriptor_config.interruptType);
780 
781     Cy_DMAC_Channel_Enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
782 
783     cyhal_dest_t dest = _cyhal_dma_dmac_get_dest(obj->resource.block_num, obj->resource.channel_num);
784 
785     return _cyhal_disconnect_signal(source, dest);
786 }
787 
_cyhal_dma_dmac_disable_output(cyhal_dma_t * obj,cyhal_dma_output_t output)788 cy_rslt_t _cyhal_dma_dmac_disable_output(cyhal_dma_t *obj, cyhal_dma_output_t output)
789 {
790     if(output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT &&
791        output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST &&
792        output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS)
793         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
794 
795     Cy_DMAC_Channel_Disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
796 
797     // There is no option to totally disable. Just reset to default.
798     obj->descriptor.dmac.ctl &= ~DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE_Msk;
799     obj->descriptor.dmac.ctl |= _VAL2FLD(DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE, _cyhal_dma_dmac_default_descriptor_config.triggerOutType);
800 
801     Cy_DMAC_Channel_Enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
802 
803     return CY_RSLT_SUCCESS;
804 
805 }
806 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
807 
_cyhal_dma_dmac_connect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)808 cy_rslt_t _cyhal_dma_dmac_connect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
809 {
810     if((input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT) &&
811        (input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS))
812         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
813 
814     Cy_DMAC_Channel_SetCurrentDescriptor(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num, obj->descriptor);
815 
816     cyhal_dest_t dest = (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + obj->resource.channel_num);
817 
818     return _cyhal_connect_signal(source, dest);
819 }
820 
821 // M0S8 output triggers are always active. This is a noop except to return the source.
_cyhal_dma_dmac_enable_output(cyhal_dma_t * obj,cyhal_dma_output_t output,cyhal_source_t * source)822 cy_rslt_t _cyhal_dma_dmac_enable_output(cyhal_dma_t *obj, cyhal_dma_output_t output, cyhal_source_t *source)
823 {
824     if((output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT) &&
825        (output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS))
826         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
827 
828     *source = _cyhal_dma_dmac_get_src(obj->resource.block_num, obj->resource.channel_num);
829 
830     return CY_RSLT_SUCCESS;
831 }
832 
_cyhal_dma_dmac_disconnect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)833 cy_rslt_t _cyhal_dma_dmac_disconnect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
834 {
835     if((input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT) &&
836        (input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS))
837         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
838 
839     // Reset to default
840     Cy_DMAC_Channel_SetCurrentDescriptor(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num, obj->descriptor);
841 
842     cyhal_dest_t dest = (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + obj->resource.channel_num);
843 
844     return _cyhal_disconnect_signal(source, dest);
845 }
846 
847 // M0S8 output triggers are always active. This is a noop.
_cyhal_dma_dmac_disable_output(cyhal_dma_t * obj,cyhal_dma_output_t output)848 cy_rslt_t _cyhal_dma_dmac_disable_output(cyhal_dma_t *obj, cyhal_dma_output_t output)
849 {
850     CY_UNUSED_PARAMETER(obj);
851 
852     if((output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT) &&
853        (output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS))
854         return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
855 
856     return CY_RSLT_SUCCESS;
857 }
858 
859 #endif /* defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) */
860 
861 #endif /* (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC) */
862 
863 #if defined(__cplusplus)
864 }
865 #endif
866