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-2022 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_irq_impl.h"
35 #include "cyhal_triggers.h"
36
37 #if defined(__cplusplus)
38 extern "C" {
39 #endif
40
41 #if (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC)
42
43 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC)
44 #define DMAC0_IRQn (cpuss_interrupts_dmac_0_IRQn)
45 #define GET_RESOURCE_DATA(x) (x.dmac)
46 typedef DMAC_Type cyhal_dmac_hw_type;
47 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
48 #define DMAC0_IRQn (cpuss_interrupt_dma_IRQn)
49 #define GET_RESOURCE_DATA(x) (x)
50 #define CY_TRIGGER_TWO_CYCLES (2)
51 typedef DMAC_Type cyhal_dmac_hw_type;
52 #elif defined(CY_IP_MXAHBDMAC)
53 #define DMAC0_IRQn (cpuss_interrupts_dmac0_0_IRQn)
54 #define DMAC1_IRQn (cpuss_interrupts_dmac1_0_IRQn)
55 #define GET_RESOURCE_DATA(x) (x.dmac)
56 typedef MXAHBDMAC_Type cyhal_dmac_hw_type;
57 #elif defined(CY_IP_MXSAXIDMAC)
58 #define DMAC0_IRQn (m55appcpuss_interrupts_axidmac_0_IRQn)
59 typedef SAXI_DMAC_Type cyhal_dmac_hw_type;
60 #define GET_RESOURCE_DATA(x) (x.dmac)
61 #endif
62
63 #if defined (AXI_DMAC_CH_NR)
64 #if APPCPUSS_AXIDMAC1_PRESENT
65 #define NUM_DMAC0_CHANNELS (APPCPUSS_AXIDMAC0_CH_NR)
66 #define NUM_DMAC_CHANNELS (APPCPUSS_AXIDMAC0_CH_NR + APPCPUSS_AXIDMAC1_CH_NR)
67 #else
68 #define NUM_DMAC0_CHANNELS (APPCPUSS_AXIDMAC0_CH_NR)
69 #define NUM_DMAC_CHANNELS (APPCPUSS_AXIDMAC0_CH_NR)
70 #endif
71 #elif defined(CPUSS_DMAC0_CH_NR) && defined(CPUSS_DMAC1_CH_NR) && (CPUSS_DMAC0_PRESENT > 0) && (CPUSS_DMAC1_PRESENT > 0)
72 #define NUM_DMAC_CHANNELS (CPUSS_DMAC0_CH_NR + CPUSS_DMAC1_CH_NR)
73 #define NUM_DMAC0_CHANNELS (CPUSS_DMAC0_CH_NR)
74 #elif defined(CPUSS_DMAC_CH_NR)
75 #define NUM_DMAC_CHANNELS (CPUSS_DMAC_CH_NR)
76 #define CPUSS_DMAC0_CH_NR (CPUSS_DMAC_CH_NR)
77 #define NUM_DMAC0_CHANNELS (CPUSS_DMAC_CH_NR)
78 #define CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 (CYHAL_TRIGGER_CPUSS_DMAC_TR_IN0)
79 #define _CYHAL_TRIGGER_CPUSS_DMAC0_TR_OUT0 (_CYHAL_TRIGGER_CPUSS_DMAC_TR_OUT0)
80 #endif
81
82 //Wrappers for PDL functions and Macros for AXI DMAC differences
83 #if defined(CY_IP_MXSAXIDMAC)
84 #define _cyhal_dmac_channel_enable(base, channel) Cy_AXIDMAC_Channel_Enable(base, channel)
85 #define _cyhal_dmac_channel_disable(base, channel) Cy_AXIDMAC_Channel_Disable(base, channel)
86 #define _cyhal_dmac_get_active_channel(base) Cy_AXIDMAC_GetActiveChannel(base)
87 #define _cyhal_dmac_channel_get_interrupt_status_masked(base, channel) Cy_AXIDMAC_Channel_GetInterruptStatusMasked(base, channel)
88 #define _CYHAL_DMAC_CHANNEL_ENABLED (CY_AXIDMAC_CHANNEL_ENABLED)
89 #define _CYHAL_DMAC_CHANNEL_DISABLED (CY_AXIDMAC_CHANNEL_DISABLED)
90 #define _CYHAL_DMAC_DESCR (CY_AXIDMAC_DESCR)
91 #define _CYHAL_DMAC_M_LOOP (CY_AXIDMAC_M_LOOP)
92 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Msk (SAXI_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Msk)
93 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Msk (SAXI_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Msk)
94 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE (SAXI_DMAC_CH_DESCR_CTL_TR_IN_TYPE)
95 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE (SAXI_DMAC_CH_DESCR_CTL_TR_OUT_TYPE)
96 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Pos (SAXI_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Pos)
97 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Pos (SAXI_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Pos)
98 #define _CYHAL_TRIGGER_CPUSS_ZERO (CYHAL_TRIGGER_M33SYSCPUSS_ZERO)
99 #elif defined(CY_IP_MXAHBDMAC) || defined(CY_IP_M0S8CPUSSV3_DMAC) || defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC)
100 #define _cyhal_dmac_channel_enable(base, channel) Cy_DMAC_Channel_Enable(base, channel)
101 #define _cyhal_dmac_channel_disable(base, channel) Cy_DMAC_Channel_Disable(base, channel)
102 #define _cyhal_dmac_get_active_channel(base) Cy_DMAC_GetActiveChannel(base)
103 #define _cyhal_dmac_channel_get_interrupt_status_masked(base, channel) Cy_DMAC_Channel_GetInterruptStatusMasked(base, channel)
104 #define _CYHAL_DMAC_CHANNEL_ENABLED (CY_DMAC_CHANNEL_ENABLED)
105 #define _CYHAL_DMAC_CHANNEL_DISABLED (CY_DMAC_CHANNEL_DISABLED)
106 #define _CYHAL_DMAC_DESCR (CY_DMAC_DESCR)
107 #define _CYHAL_DMAC_X_LOOP (CY_DMAC_X_LOOP)
108 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Msk (DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE_Msk)
109 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Msk (DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE_Msk)
110 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE (DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE)
111 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE (DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE)
112 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Pos (DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE_Pos)
113 #define _CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Pos (DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE_Pos)
114 #define _CYHAL_TRIGGER_CPUSS_ZERO (CYHAL_TRIGGER_CPUSS_ZERO)
115 #endif
116
117
118 static cyhal_dma_t* _cyhal_dma_dmac_config_structs[NUM_DMAC_CHANNELS];
119
120 /** Default dmac descriptor config */
121 #if defined(CY_IP_MXSAXIDMAC)
122 static const cy_stc_axidmac_descriptor_config_t _cyhal_dma_dmac_default_descriptor_config =
123 #else
124 static const cy_stc_dmac_descriptor_config_t _cyhal_dma_dmac_default_descriptor_config =
125 #endif
126 {
127 .srcAddress = 0, // Overriden by cyhal_dma_cfg_t.src_addr
128 .dstAddress = 0, // Overriden by cyhal_dma_cfg_t.dst_addr
129 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
130 .dataSize = CY_DMAC_WORD, // Overridden by cyhal_dma_cfg_t.transfer_width
131 .dstTransferSize = CY_DMAC_TRANSFER_SIZE_DATA, // Overriden by direction
132 .srcTransferSize = CY_DMAC_TRANSFER_SIZE_DATA, // Overriden by direction
133 .retrigger = CY_DMAC_RETRIG_IM,
134 .interruptType = CY_DMAC_DESCR, // Overridden by cyhal_dma_cfg_t.action
135 .triggerOutType = CY_DMAC_DESCR_CHAIN, // Overridden by [en/dis]able_output()
136 .channelState = CY_DMAC_CHANNEL_ENABLED,
137 .triggerInType = CY_DMAC_DESCR, // Overridden by cyhal_dma_cfg_t.action & [dis]connect_digital()
138 .dataPrefetch = false,
139 .descriptorType = CY_DMAC_1D_TRANSFER, // Overriden by cyhal_dma_cfg_t.burst_size
140 .srcXincrement = 1U, // Overriden by cyhal_dma_cfg_t.src_increment
141 .dstXincrement = 1U, // Overriden by cyhal_dma_cfg_t.dst_increment
142 .xCount = 1UL, // Overriden by cyhal_dma_cfg_t.length/burst_size
143 .srcYincrement = 1U, // Overriden by cyhal_dma_cfg_t.burst_size
144 .dstYincrement = 1U, // Overriden by cyhal_dma_cfg_t.burst_size
145 .yCount = 1UL, // Overriden by cyhal_dma_cfg_t.length
146 .nextDescriptor = 0,
147 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
148 .dataSize = CY_DMAC_WORD, // Overridden by cyhal_dma_cfg_t.transfer_width
149 .dstTransferSize = CY_DMAC_TRANSFER_SIZE_DATA, // Overriden by direction
150 .srcTransferSize = CY_DMAC_TRANSFER_SIZE_DATA, // Overriden by direction
151 .retrigger = CY_DMAC_RETRIG_IM,
152 .triggerType = CY_DMAC_SINGLE_DESCR,
153 .dataCount = 1, // Overriden by cyhal_dma_cfg_t.length
154 .dstAddrIncrement = true, // Overriden by cyhal_dma_cfg_t.dst_increment
155 .srcAddrIncrement = true, // Overriden by cyhal_dma_cfg_t.src_increment
156 .interrupt = true,
157 .preemptable = true,
158 .flipping = false,
159 #elif defined(CY_IP_MXSAXIDMAC)
160 .retrigger = CY_AXIDMAC_RETRIG_IM,
161 .interruptType = CY_AXIDMAC_DESCR, // Overridden by cyhal_dma_cfg_t.action
162 .triggerOutType = CY_AXIDMAC_DESCR_CHAIN, // Overridden by [en/dis]able_output()
163 .channelState = CY_AXIDMAC_CHANNEL_DISABLED,
164 .triggerInType = CY_AXIDMAC_DESCR, // Overridden by cyhal_dma_cfg_t.action & [dis]connect_digital()
165 .dataPrefetch = false,
166 .descriptorType = CY_AXIDMAC_1D_MEMORY_COPY, // Overriden by cyhal_dma_cfg_t.burst_size
167 .mCount = 1U, // Overriden by cyhal_dma_cfg_t.length
168 .srcXincrement = 0U, // Overriden by cyhal_dma_cfg_t.src_increment
169 .dstXincrement = 0U, // Overriden by cyhal_dma_cfg_t.dst_increment
170 .xCount = 1UL, // Overriden by cyhal_dma_cfg_t.length/burst_size
171 .srcYincrement = 0U,
172 .dstYincrement = 0U,
173 .yCount = 1UL,
174 .nextDescriptor = NULL,
175 #endif
176 };
177
178 /** Default dmac channel config */
179 #if defined(CY_IP_MXSAXIDMAC)
180 static const cy_stc_axidmac_channel_config_t _cyhal_dma_dmac_default_channel_config =
181 #else
182 static const cy_stc_dmac_channel_config_t _cyhal_dma_dmac_default_channel_config =
183 #endif
184 {
185 .priority = 1, // Overriden by config().priority
186 .enable = false,
187 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
188 .bufferable = false,
189 .descriptor = 0, // Overriden by config()
190 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
191 .descriptor = CY_DMAC_DESCRIPTOR_PING, // Overriden by config()
192 #endif
193 };
194
195 static bool _cyhal_dma_dmac_pm_transition_pending = false;
196
197 #if CYHAL_DRIVER_AVAILABLE_SYSPM
198 static bool _cyhal_dma_dmac_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg);
199
200 static cyhal_syspm_callback_data_t _cyhal_dma_dmac_pm_callback_args = {
201 .callback = &_cyhal_dma_dmac_pm_callback,
202 .states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE),
203 .next = NULL,
204 .args = NULL,
205 .ignore_modes = (cyhal_syspm_callback_mode_t)(CYHAL_SYSPM_BEFORE_TRANSITION | CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION),
206 };
207
_cyhal_dma_dmac_has_enabled(void)208 static bool _cyhal_dma_dmac_has_enabled(void)
209 {
210 for (uint8_t i = 0; i < NUM_DMAC_CHANNELS; i++)
211 if (NULL != _cyhal_dma_dmac_config_structs[i])
212 return true;
213 return false;
214 }
215
_cyhal_dma_dmac_pm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)216 static bool _cyhal_dma_dmac_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg)
217 {
218 CY_UNUSED_PARAMETER(state);
219 CY_UNUSED_PARAMETER(callback_arg);
220 bool block_transition = false;
221 switch(mode)
222 {
223 case CYHAL_SYSPM_CHECK_READY:
224 for (uint8_t i = 0; (i < NUM_DMAC_CHANNELS) && !block_transition; i++)
225 {
226 block_transition |= (_cyhal_dma_dmac_config_structs[i] != NULL) && _cyhal_dma_dmac_is_busy(_cyhal_dma_dmac_config_structs[i]);
227 }
228 _cyhal_dma_dmac_pm_transition_pending = !block_transition;
229 break;
230 case CYHAL_SYSPM_CHECK_FAIL:
231 case CYHAL_SYSPM_AFTER_TRANSITION:
232 _cyhal_dma_dmac_pm_transition_pending = false;
233 break;
234 default:
235 CY_ASSERT(false);
236 break;
237 }
238 return _cyhal_dma_dmac_pm_transition_pending;
239 }
240 #endif
241
242 /** Gets the dmac configuration struct offset */
_cyhal_dma_dmac_get_cfg_offset(const cyhal_dma_t * obj)243 static inline uint8_t _cyhal_dma_dmac_get_cfg_offset(const cyhal_dma_t* obj)
244 {
245 return (obj->resource.block_num * NUM_DMAC0_CHANNELS) + obj->resource.channel_num;
246 }
247
248 /** Sets the dmac configuration struct */
_cyhal_dma_dmac_set_obj(cyhal_dma_t * obj)249 static inline void _cyhal_dma_dmac_set_obj(cyhal_dma_t *obj)
250 {
251 _cyhal_dma_dmac_config_structs[_cyhal_dma_dmac_get_cfg_offset(obj)] = obj;
252 }
253
254 /** Zeros the dmac configuration struct */
_cyhal_dma_dmac_free_obj(cyhal_dma_t * obj)255 static inline void _cyhal_dma_dmac_free_obj(cyhal_dma_t *obj)
256 {
257 _cyhal_dma_dmac_config_structs[_cyhal_dma_dmac_get_cfg_offset(obj)] = NULL;
258 }
259
260 /** Gets the dmac configuration struct from block and channel */
_cyhal_dma_dmac_get_obj(uint8_t block,uint8_t channel)261 static inline cyhal_dma_t* _cyhal_dma_dmac_get_obj(uint8_t block, uint8_t channel)
262 {
263 #if defined(CY_IP_MXSAXIDMAC)
264 return _cyhal_dma_dmac_config_structs[(block * APPCPUSS_AXIDMAC0_CH_NR) + channel];
265 #else
266 return _cyhal_dma_dmac_config_structs[(block * CPUSS_DMAC0_CH_NR) + channel];
267 #endif
268 }
269
270 /** Gets the dmac block number from irq number */
271 /** This should never be called from a non-dma IRQn */
_cyhal_dma_dmac_get_block_from_irqn(_cyhal_system_irq_t irqn)272 static inline uint8_t _cyhal_dma_dmac_get_block_from_irqn(_cyhal_system_irq_t irqn)
273 {
274 uint8_t diff = irqn - DMAC0_IRQn;
275 CY_ASSERT(diff < NUM_DMAC_CHANNELS);
276 if (diff < NUM_DMAC0_CHANNELS)
277 return 0;
278 #if (NUM_DMAC0_CHANNELS < NUM_DMAC_CHANNELS)
279 if (diff < NUM_DMAC_CHANNELS)
280 return 1;
281 #endif
282 else
283 {
284 // Should never reach here. Just silencing compiler warnings.
285 CY_ASSERT(false);
286 return 0xFF;
287 }
288 }
289
290 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
291 /** Gets the dmac channel number from irq number */
292 /** This should never be called from a non-dma IRQn */
_cyhal_dma_dmac_get_channel_from_irqn(_cyhal_system_irq_t irqn)293 static inline uint8_t _cyhal_dma_dmac_get_channel_from_irqn(_cyhal_system_irq_t irqn)
294 {
295 uint8_t diff = irqn - DMAC0_IRQn;
296 CY_ASSERT(diff < NUM_DMAC_CHANNELS);
297 if (diff < NUM_DMAC0_CHANNELS)
298 return diff;
299 #if (NUM_DMAC0_CHANNELS < NUM_DMAC_CHANNELS)
300 else
301 return diff - NUM_DMAC0_CHANNELS;
302 #endif
303 // Should never reach here. Just silencing compiler warnings.
304 CY_ASSERT(false);
305 return 0xFF;
306 }
307 #endif
308
309 /** Gets the irqn corresponding to a particular cyhal_dma_t config struct */
_cyhal_dma_dmac_get_irqn(cyhal_dma_t * obj)310 static inline _cyhal_system_irq_t _cyhal_dma_dmac_get_irqn(cyhal_dma_t *obj)
311 {
312 #if defined(CY_IP_M0S8CPUSSV3_DMAC)
313 CY_UNUSED_PARAMETER(obj);
314 /* This IP has a single ganged IRQ for all DMA channels */
315 return DMAC0_IRQn;
316 #else
317 return (_cyhal_system_irq_t)((uint8_t)DMAC0_IRQn + _cyhal_dma_dmac_get_cfg_offset(obj));
318 #endif
319 }
320
321 /** Gets the dmac base pointer from block number */
_cyhal_dma_dmac_get_base(uint8_t block_num)322 static inline cyhal_dmac_hw_type* _cyhal_dma_dmac_get_base(uint8_t block_num)
323 {
324 #if defined(CY_IP_MXSAXIDMAC)
325 CY_UNUSED_PARAMETER(block_num);
326 return SAXI_DMAC;
327 #elif defined(CPUSS_DMAC0_CH_NR) && !defined(CPUSS_DMAC1_CH_NR)
328 CY_UNUSED_PARAMETER(block_num);
329 return DMAC;
330 #elif defined(CPUSS_DMAC0_CH_NR) && defined(CPUSS_DMAC1_CH_NR)
331 return (block_num == 0) ? MXAHBDMAC0 : MXAHBDMAC1;
332 #else
333 //Should never get here
334 #error "Error: No corresponding base type"
335 #endif
336 }
337
338 /** Uses tables provided as part of the hal interconnect driver to determine mux
339 * trigger group and mux trigger index and then construct the trigger line
340 * input parameter to Cy_TrigMux_SwTrigger. */
_cyhal_dma_dmac_get_trigger_line(uint8_t block_num,uint8_t channel_num)341 static inline uint32_t _cyhal_dma_dmac_get_trigger_line(uint8_t block_num, uint8_t channel_num)
342 {
343 /* cyhal_dest_t triggers are guaranteed to be sorted by trigger type, block
344 * num, then channel num, therefore, we can just directly find the proper
345 * trigger by calculating an offset. */
346 #if defined(CY_IP_MXSAXIDMAC)
347 cyhal_dest_t trigger = (cyhal_dest_t)(CYHAL_TRIGGER_M55APPCPUSS_AXIDMAC_TR_IN0 + (block_num * APPCPUSS_AXIDMAC0_CH_NR) + channel_num);
348 #else
349 cyhal_dest_t trigger = (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + (block_num * CPUSS_DMAC0_CH_NR) + channel_num);
350 #endif
351 uint32_t trigger_line = 0;
352
353 /* One to one triggers have bit 8 set in cyhal_dest_to_mux but
354 * Cy_TrigMux_SwTrigger wants the trigger group field to have bit 5 set to
355 * denote one to one triggers. */
356 uint8_t trig_group = cyhal_dest_to_mux[trigger];
357 /* If hal one to one triggers bit is set: mask it out and set pdl one to
358 * one bit */
359 if(trig_group & _CYHAL_DMA_TRIGGERS_1TO1_MASK)
360 trig_group = (trig_group & ~_CYHAL_DMA_TRIGGERS_1TO1_MASK) | _CYHAL_DMA_PDL_TRIGGERS_1TO1_MASK;
361
362 /* Construct trigger line which consists of three fields packed into a
363 * uint32_t:
364 * Bits 30: Input/output bit. Set to 1 for output.
365 * Bits 12-8: Trigger group selection.
366 * Bits 7-0: Select the output trigger number in the trigger group. */
367 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
368 trigger_line = PERI_TR_CMD_OUT_SEL_Msk | ((uint32_t)trig_group << 8) | cyhal_mux_dest_index[trigger];
369 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
370 trigger_line = PERI_TR_CTL_TR_OUT_Msk | ((uint32_t)trig_group << 8) | cyhal_mux_dest_index[trigger];
371 #endif
372
373 #if (((CY_IP_MXSPERI_INSTANCES) == 2U) && defined(CY_IP_MXSAXIDMAC))
374 /* Bits 16: The PERI 1 instance.
375 The trigger input for AXIDMAC is located on PERI 1
376 */
377 trigger_line |= PERI_INSTANCE_1_IDENT_Msk;
378 #endif
379
380 return trigger_line;
381 }
382
383 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
384 /** Convert PDL interrupt cause to hal dma event */
_cyhal_dma_dmac_convert_interrupt_cause(cyhal_dma_t * obj,uint32_t cause)385 static inline cyhal_dma_event_t _cyhal_dma_dmac_convert_interrupt_cause(cyhal_dma_t *obj, uint32_t cause)
386 {
387 static const cyhal_dma_event_t hal[] =
388 {
389 CYHAL_DMA_TRANSFER_COMPLETE,
390 CYHAL_DMA_SRC_BUS_ERROR,
391 CYHAL_DMA_DST_BUS_ERROR,
392 CYHAL_DMA_SRC_MISAL,
393 CYHAL_DMA_DST_MISAL,
394 CYHAL_DMA_CURR_PTR_NULL,
395 CYHAL_DMA_ACTIVE_CH_DISABLED,
396 CYHAL_DMA_DESCR_BUS_ERROR
397 };
398
399 cyhal_dma_event_t hal_rslt = CYHAL_DMA_NO_INTR;
400 for (uint8_t i = 0; cause > 0 && i < sizeof(hal)/sizeof(cyhal_dma_event_t); i++)
401 {
402 if ((cause & (1 << i)) > 0)
403 hal_rslt |= hal[i];
404 }
405
406 if ((uint32_t)(hal_rslt & CYHAL_DMA_TRANSFER_COMPLETE) > 0 && obj->expected_bursts > 0)
407 {
408 obj->expected_bursts--;
409 if (0 == obj->expected_bursts)
410 {
411 hal_rslt |= CYHAL_DMA_DESCRIPTOR_COMPLETE;
412 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
413 obj->expected_bursts = (GET_RESOURCE_DATA(obj->descriptor_config).interruptType == _CYHAL_DMAC_X_LOOP)
414 ? GET_RESOURCE_DATA(obj->descriptor_config).yCount
415 : 1;
416 #elif defined(CY_IP_MXSAXIDMAC)
417 obj->expected_bursts = (GET_RESOURCE_DATA(obj->descriptor_config).interruptType == _CYHAL_DMAC_M_LOOP)
418 ? GET_RESOURCE_DATA(obj->descriptor_config).xCount
419 : 1;
420 #else
421 obj->expected_bursts = 1;
422 #endif
423 }
424 }
425
426 return hal_rslt;
427 }
428 #endif
429
430 /** DMAC irq handler */
_cyhal_dma_dmac_irq_handler(void)431 static void _cyhal_dma_dmac_irq_handler(void)
432 {
433 /* Use irqn to get appropriate config structure */
434 _cyhal_system_irq_t irqn = _cyhal_irq_get_active();
435 uint8_t block = _cyhal_dma_dmac_get_block_from_irqn(irqn);
436 #if defined(CY_IP_MXSAXIDMAC)
437 SAXI_DMAC_Type* base = _cyhal_dma_dmac_get_base(block);
438 #else
439 DMAC_Type* base = _cyhal_dma_dmac_get_base(block);
440 #endif
441 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
442 uint8_t channel = _cyhal_dma_dmac_get_channel_from_irqn(irqn);
443 cyhal_dma_t *obj = _cyhal_dma_dmac_get_obj(block, channel);
444
445 /* Get interrupt type and call users event callback if they have enabled that event */
446 uint32_t cause = _cyhal_dmac_channel_get_interrupt_status_masked(base, channel);
447 cyhal_dma_event_t event_type = _cyhal_dma_dmac_convert_interrupt_cause(obj, cause);
448 uint32_t events_to_callback = event_type & obj->irq_cause;
449 if(obj->callback_data.callback != NULL && events_to_callback)
450 {
451 ((cyhal_dma_event_callback_t)obj->callback_data.callback)(obj->callback_data.callback_arg, (cyhal_dma_event_t)events_to_callback);
452 }
453
454 /* Clear all interrupts */
455 #if defined(CY_IP_MXSAXIDMAC)
456 Cy_AXIDMAC_Channel_ClearInterrupt(base, channel, CY_AXIDMAC_INTR_MASK);
457 #else
458 Cy_DMAC_Channel_ClearInterrupt(base, channel, CY_DMAC_INTR_MASK);
459 #endif
460 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
461 uint32_t channels = Cy_DMAC_GetInterruptStatusMasked(base);
462 for(int i = 0 ; ((uint32_t)(1 << i)) <= channels ; i++)
463 {
464 cyhal_dma_t *obj = _cyhal_dma_dmac_get_obj(block, i);
465 if (obj != NULL)
466 {
467 if (((channels & (1 << i)) != 0) && (obj->callback_data.callback != NULL))
468 {
469 ((cyhal_dma_event_callback_t)obj->callback_data.callback)(obj->callback_data.callback_arg, CYHAL_DMA_TRANSFER_COMPLETE);
470 }
471 }
472 }
473 Cy_DMAC_ClearInterrupt(_cyhal_dma_dmac_get_base(block), channels);
474 #endif
475 }
476
_cyhal_dma_dmac_get_src(uint8_t block_num,uint8_t channel_num)477 static cyhal_source_t _cyhal_dma_dmac_get_src(uint8_t block_num, uint8_t channel_num)
478 {
479 #if defined(CY_IP_MXSAXIDMAC)
480 return (cyhal_source_t)_CYHAL_TRIGGER_CREATE_SOURCE((_CYHAL_TRIGGER_M55APPCPUSS_AXIDMAC_TR_OUT0 + (block_num * APPCPUSS_AXIDMAC0_CH_NR) + channel_num), CYHAL_SIGNAL_TYPE_EDGE);
481 #else
482 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);
483 #endif
484 }
485
_cyhal_dma_dmac_get_dest(uint8_t block_num,uint8_t channel_num)486 static cyhal_dest_t _cyhal_dma_dmac_get_dest(uint8_t block_num, uint8_t channel_num)
487 {
488 #if defined(CY_IP_MXSAXIDMAC)
489 return (cyhal_dest_t)(CYHAL_TRIGGER_M55APPCPUSS_AXIDMAC_TR_IN0 + (block_num * APPCPUSS_AXIDMAC0_CH_NR) + channel_num);
490 #else
491 return (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + (block_num * CPUSS_DMAC0_CH_NR) + channel_num);
492 #endif
493 }
494
_cyhal_dma_dmac_stage(cyhal_dma_t * obj)495 static cy_rslt_t _cyhal_dma_dmac_stage(cyhal_dma_t *obj)
496 {
497 cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
498 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
499 #if (CY_CPU_CORTEX_M7) && defined (ENABLE_CM7_DATA_CACHE)
500 SCB_CleanDCache_by_Addr((void *)&(obj->descriptor), sizeof(obj->descriptor));
501 #endif /* (CY_CPU_CORTEX_M7) && defined (ENABLE_CM7_DATA_CACHE) */
502 #if defined(CY_IP_MXSAXIDMAC)
503 cy_en_axidmac_descriptor_type_t descr_type = GET_RESOURCE_DATA(&obj->descriptor_config)->descriptorType;
504 GET_RESOURCE_DATA(&obj->descriptor_config)->descriptorType = CY_AXIDMAC_3D_MEMORY_COPY;
505 cy_rslt_t rslt = Cy_AXIDMAC_Descriptor_Init(GET_RESOURCE_DATA(&obj->descriptor), GET_RESOURCE_DATA(&obj->descriptor_config));
506 Cy_AXIDMAC_Descriptor_SetDescriptorType(GET_RESOURCE_DATA(&obj->descriptor), descr_type);
507 GET_RESOURCE_DATA(&obj->descriptor_config)->descriptorType = descr_type;
508 #else
509 cy_rslt_t rslt = Cy_DMAC_Descriptor_Init(GET_RESOURCE_DATA(&obj->descriptor), GET_RESOURCE_DATA(&obj->descriptor_config));
510 #endif
511 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
512 cy_rslt_t rslt = Cy_DMAC_Descriptor_Init(base, obj->resource.channel_num, obj->descriptor, GET_RESOURCE_DATA(&obj->descriptor_config));
513 #endif
514 #if defined(CY_IP_MXSAXIDMAC)
515 if(CY_AXIDMAC_SUCCESS != rslt)
516 #else
517 if(CY_DMAC_SUCCESS != rslt)
518 #endif
519 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
520
521 /* Setup channel and enable */
522 #if (CY_CPU_CORTEX_M7) && defined (ENABLE_CM7_DATA_CACHE)
523 SCB_CleanDCache_by_Addr((void *)&(obj->channel_config), sizeof(obj->channel_config));
524 #endif /* (CY_CPU_CORTEX_M7) && defined (ENABLE_CM7_DATA_CACHE) */
525 #if defined(CY_IP_MXSAXIDMAC)
526 if(CY_AXIDMAC_SUCCESS != Cy_AXIDMAC_Channel_Init(base, obj->resource.channel_num, GET_RESOURCE_DATA(&obj->channel_config)))
527 #else
528 if(CY_DMAC_SUCCESS != Cy_DMAC_Channel_Init(base, obj->resource.channel_num, GET_RESOURCE_DATA(&obj->channel_config)))
529 #endif
530 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
531
532 #if defined(CY_IP_MXSAXIDMAC)
533 Cy_AXIDMAC_Channel_SetInterruptMask(base, obj->resource.channel_num, CY_AXIDMAC_INTR_MASK);
534 #elif defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
535 Cy_DMAC_Channel_SetInterruptMask(base, obj->resource.channel_num, CY_DMAC_INTR_MASK);
536 #endif
537 #if defined(CY_IP_MXSAXIDMAC)
538 Cy_AXIDMAC_Enable(base);
539 #else
540 Cy_DMAC_Enable(base);
541 #endif
542
543 #if defined(CY_IP_MXSAXIDMAC)
544 /* src_misal and dst_misal interrupts are triggered immediately on enable
545 * so return those errors here */
546 uint32_t status = Cy_AXIDMAC_Channel_GetInterruptStatus(base, obj->resource.channel_num);
547 if((status & CY_AXIDMAC_INTR_INVALID_DESCR_TYPE))
548 {
549 /* Clear all interrupts and return error */
550 Cy_AXIDMAC_Channel_ClearInterrupt(base, obj->resource.channel_num, CY_AXIDMAC_INTR_MASK);
551 return CYHAL_DMA_RSLT_ERR_INVALID_ALIGNMENT;
552 }
553 #elif defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
554 /* src_misal and dst_misal interrupts are triggered immediately on enable
555 * so return those errors here */
556 uint32_t status = Cy_DMAC_Channel_GetInterruptStatus(base, obj->resource.channel_num);
557 if((status & CY_DMAC_INTR_SRC_MISAL) ||
558 (status & CY_DMAC_INTR_DST_MISAL))
559 {
560 /* Clear all interrupts and return error */
561 Cy_DMAC_Channel_ClearInterrupt(base, obj->resource.channel_num, CY_DMAC_INTR_MASK);
562 return CYHAL_DMA_RSLT_ERR_INVALID_ALIGNMENT;
563 }
564 #endif
565
566 /* Enable interrupt for this channel; preserve user priority if they enabled an interrupt */
567 _cyhal_system_irq_t irqn = _cyhal_dma_dmac_get_irqn(obj);
568 uint32_t priority = (CYHAL_DMA_NO_INTR == obj->irq_cause)
569 ? CYHAL_ISR_PRIORITY_DEFAULT
570 : _cyhal_irq_get_priority(irqn);
571
572 if(CY_RSLT_SUCCESS != _cyhal_irq_register(irqn, priority, _cyhal_dma_dmac_irq_handler))
573 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
574 _cyhal_irq_enable(irqn);
575
576 return CY_RSLT_SUCCESS;
577 }
578
_cyhal_dma_dmac_init(cyhal_dma_t * obj,cyhal_source_t * src,cyhal_dest_t * dest,uint8_t priority)579 cy_rslt_t _cyhal_dma_dmac_init(cyhal_dma_t *obj, cyhal_source_t *src, cyhal_dest_t *dest, uint8_t priority)
580 {
581
582 #if defined(CY_IP_MXSAXIDMAC)
583 if(!CY_AXIDMAC_IS_PRIORITY_VALID(priority))
584 #else
585 if(!CY_DMAC_IS_PRIORITY_VALID(priority))
586 #endif
587 return CYHAL_DMA_RSLT_ERR_INVALID_PRIORITY;
588
589 if (_cyhal_dma_dmac_pm_transition_pending)
590 {
591 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
592 }
593
594 cy_rslt_t rslt = _cyhal_hwmgr_allocate_with_connection(
595 CYHAL_RSC_DMA, src, dest, _cyhal_dma_dmac_get_src, _cyhal_dma_dmac_get_dest, &obj->resource);
596 if(rslt != CY_RSLT_SUCCESS)
597 return rslt;
598
599 obj->callback_data.callback = NULL;
600
601 /* Setup descriptor and channel configs */
602 GET_RESOURCE_DATA(obj->descriptor_config) = _cyhal_dma_dmac_default_descriptor_config;
603 GET_RESOURCE_DATA(obj->channel_config) = _cyhal_dma_dmac_default_channel_config;
604 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
605 GET_RESOURCE_DATA(obj->channel_config).descriptor = GET_RESOURCE_DATA(&obj->descriptor);
606 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
607 obj->descriptor = obj->channel_config.descriptor;
608 #endif
609 GET_RESOURCE_DATA(obj->channel_config).priority = priority;
610
611 #if CYHAL_DRIVER_AVAILABLE_SYSPM
612 if (!_cyhal_dma_dmac_has_enabled())
613 {
614 _cyhal_syspm_register_peripheral_callback(&_cyhal_dma_dmac_pm_callback_args);
615 }
616 #endif
617
618 _cyhal_dma_dmac_set_obj(obj);
619
620 return CY_RSLT_SUCCESS;
621 }
622
_cyhal_dma_dmac_init_cfg(cyhal_dma_t * obj,const cyhal_dma_configurator_t * cfg)623 cy_rslt_t _cyhal_dma_dmac_init_cfg(cyhal_dma_t *obj, const cyhal_dma_configurator_t *cfg)
624 {
625 if (_cyhal_dma_dmac_pm_transition_pending)
626 {
627 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
628 }
629
630 obj->resource = *(cfg->resource);
631 obj->callback_data.callback = NULL;
632
633 /* Setup descriptor and channel configs */
634 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
635 obj->descriptor_config.dmac = *(cfg->dmac_descriptor_config);
636 obj->channel_config.dmac = *(cfg->dmac_channel_config);
637 GET_RESOURCE_DATA(obj->channel_config).descriptor = GET_RESOURCE_DATA(&obj->descriptor);
638 #if defined(CY_IP_MXSAXIDMAC)
639 obj->expected_bursts = cfg->dmac_descriptor_config->xCount;
640 #else
641 obj->expected_bursts = cfg->dmac_descriptor_config->yCount;
642 #endif
643 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
644 obj->descriptor_config = *(cfg->descriptor_config);
645 obj->channel_config = *(cfg->channel_config);
646 obj->descriptor = obj->channel_config.descriptor;
647 obj->expected_bursts = 1;
648 #endif
649
650 #if CYHAL_DRIVER_AVAILABLE_SYSPM
651 if (!_cyhal_dma_dmac_has_enabled())
652 {
653 _cyhal_syspm_register_peripheral_callback(&_cyhal_dma_dmac_pm_callback_args);
654 }
655 #endif
656
657 _cyhal_dma_dmac_set_obj(obj);
658
659 return _cyhal_dma_dmac_stage(obj);
660 }
661
_cyhal_dma_dmac_free(cyhal_dma_t * obj)662 void _cyhal_dma_dmac_free(cyhal_dma_t *obj)
663 {
664 cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
665 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
666 Cy_DMAC_Descriptor_DeInit(GET_RESOURCE_DATA(&obj->descriptor));
667 Cy_DMAC_Channel_DeInit(base, obj->resource.channel_num);
668 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
669 Cy_DMAC_Descriptor_DeInit(base, obj->resource.channel_num, obj->descriptor);
670 Cy_DMAC_Channel_DeInit(base, obj->resource.channel_num);
671 #elif defined(CY_IP_MXSAXIDMAC)
672 Cy_AXIDMAC_Descriptor_DeInit(GET_RESOURCE_DATA(&obj->descriptor));
673 Cy_AXIDMAC_Channel_DeInit(base, obj->resource.channel_num);
674 #endif
675
676 _cyhal_irq_free(_cyhal_dma_dmac_get_irqn(obj));
677
678 _cyhal_dma_dmac_free_obj(obj);
679
680 #if CYHAL_DRIVER_AVAILABLE_SYSPM
681 if (!_cyhal_dma_dmac_has_enabled())
682 {
683 _cyhal_syspm_unregister_peripheral_callback(&_cyhal_dma_dmac_pm_callback_args);
684 _cyhal_dma_dmac_pm_transition_pending = false;
685 }
686 #endif
687 }
688
689 /* Initialize descriptor, initialize channel, enable channel, enable channel
690 * interrupt, and enable DMAC controller */
_cyhal_dma_dmac_configure(cyhal_dma_t * obj,const cyhal_dma_cfg_t * cfg)691 cy_rslt_t _cyhal_dma_dmac_configure(cyhal_dma_t *obj, const cyhal_dma_cfg_t *cfg)
692 {
693 uint32_t total_length = cfg->length;
694
695 /* Do not reconfigure if transfer is pending/active already */
696 if(_cyhal_dma_dmac_is_busy(obj))
697 return CYHAL_DMA_RSLT_ERR_CHANNEL_BUSY;
698
699 // DMAC only supports <=65536 byte burst and <=65536 bytes per burst
700 if ((cfg->burst_size > 65536) ||
701 ((cfg->burst_size <= 1) && (cfg->length > 65536)) ||
702 ((cfg->burst_size > 0) && (cfg->length > (cfg->burst_size * 65536))))
703 return CYHAL_DMA_RSLT_ERR_INVALID_TRANSFER_SIZE;
704
705 #if defined(CY_IP_M0S8CPUSSV3_DMAC)
706 // PSoC™ 4 devices do not support automatically disabling the channel on completion
707 if ((cfg->action == CYHAL_DMA_TRANSFER_BURST_DISABLE) ||
708 (cfg->action == CYHAL_DMA_TRANSFER_FULL_DISABLE))
709 {
710 return CYHAL_DMA_RSLT_FATAL_UNSUPPORTED_HARDWARE;
711 }
712 #endif
713
714 #if (CY_CPU_CORTEX_M7) && defined (ENABLE_CM7_DATA_CACHE)
715 SCB_CleanDCache_by_Addr((void *)cfg->src_addr, cfg->length * (cfg->transfer_width / 8));
716 SCB_CleanDCache_by_Addr((void *)cfg->dst_addr, cfg->length * (cfg->transfer_width / 8));
717 #endif /* (CY_CPU_CORTEX_M7) && defined (ENABLE_CM7_DATA_CACHE) */
718 GET_RESOURCE_DATA(obj->descriptor_config).srcAddress = (void*)cfg->src_addr;
719 GET_RESOURCE_DATA(obj->descriptor_config).dstAddress = (void*)cfg->dst_addr;
720
721 if ((cfg->transfer_width != 8) && (cfg->transfer_width != 16) && (cfg->transfer_width != 32))
722 return CYHAL_DMA_RSLT_ERR_INVALID_TRANSFER_WIDTH;
723
724 #if !defined(CY_IP_MXSAXIDMAC)
725 total_length = cfg->length;
726
727 if(cfg->transfer_width == 8)
728 GET_RESOURCE_DATA(obj->descriptor_config).dataSize = CY_DMAC_BYTE;
729 else if(cfg->transfer_width == 16)
730 GET_RESOURCE_DATA(obj->descriptor_config).dataSize = CY_DMAC_HALFWORD;
731 else if(cfg->transfer_width == 32)
732 GET_RESOURCE_DATA(obj->descriptor_config).dataSize = CY_DMAC_WORD;
733 else
734 return CYHAL_DMA_RSLT_ERR_INVALID_TRANSFER_WIDTH;
735
736 /* By default, transfer what the user set for dataSize. However, if transfering between memory
737 * and a peripheral, make sure the peripheral access is using words. */
738 GET_RESOURCE_DATA(obj->descriptor_config).srcTransferSize =
739 GET_RESOURCE_DATA(obj->descriptor_config).dstTransferSize = CY_DMAC_TRANSFER_SIZE_DATA;
740 if (obj->direction == CYHAL_DMA_DIRECTION_PERIPH2MEM)
741 GET_RESOURCE_DATA(obj->descriptor_config).srcTransferSize = CY_DMAC_TRANSFER_SIZE_WORD;
742 else if (obj->direction == CYHAL_DMA_DIRECTION_MEM2PERIPH)
743 GET_RESOURCE_DATA(obj->descriptor_config).dstTransferSize = CY_DMAC_TRANSFER_SIZE_WORD;
744 #else
745 /* Need to convert number of elements to the total number of bytes for transfer */
746 total_length = cfg->length * (cfg->transfer_width / 8);
747 if (!CY_AXIDMAC_IS_LOOP_COUNT_VALID(total_length))
748 {
749 return CYHAL_DMA_RSLT_ERR_INVALID_TRANSFER_SIZE;
750 }
751 #endif
752
753 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
754 GET_RESOURCE_DATA(obj->descriptor_config).nextDescriptor = GET_RESOURCE_DATA(&obj->descriptor);
755 if ((cfg->action == CYHAL_DMA_TRANSFER_BURST) || (cfg->action == CYHAL_DMA_TRANSFER_FULL))
756 {
757 GET_RESOURCE_DATA(obj->descriptor_config).channelState = _CYHAL_DMAC_CHANNEL_ENABLED;
758 }
759 else
760 {
761 GET_RESOURCE_DATA(obj->descriptor_config).channelState = _CYHAL_DMAC_CHANNEL_DISABLED;
762 }
763
764 GET_RESOURCE_DATA(obj->descriptor_config).srcXincrement = cfg->src_increment;
765 GET_RESOURCE_DATA(obj->descriptor_config).dstXincrement = cfg->dst_increment;
766
767 /* Setup 2D transfer if burst_size is being used otherwise set up 1D
768 * transfer */
769 if(cfg->burst_size != 0)
770 {
771 /* Length must be a multiple of burst_size */
772 if(total_length % cfg->burst_size != 0)
773 return CYHAL_DMA_RSLT_ERR_INVALID_BURST_SIZE;
774
775 #if defined(CY_IP_MXSAXIDMAC)
776 GET_RESOURCE_DATA(obj->descriptor_config).descriptorType = CY_AXIDMAC_2D_MEMORY_COPY;
777 GET_RESOURCE_DATA(obj->descriptor_config).mCount = cfg->burst_size * (cfg->transfer_width / 8);
778 GET_RESOURCE_DATA(obj->descriptor_config).xCount = (cfg->length / cfg->burst_size);
779 GET_RESOURCE_DATA(obj->descriptor_config).srcXincrement = cfg->src_increment * cfg->burst_size * (cfg->transfer_width / 8);
780 GET_RESOURCE_DATA(obj->descriptor_config).dstXincrement = cfg->dst_increment * cfg->burst_size * (cfg->transfer_width / 8);
781 #else
782 GET_RESOURCE_DATA(obj->descriptor_config).descriptorType = CY_DMAC_2D_TRANSFER;
783 GET_RESOURCE_DATA(obj->descriptor_config).xCount = cfg->burst_size;
784 GET_RESOURCE_DATA(obj->descriptor_config).yCount = total_length / cfg->burst_size;
785 GET_RESOURCE_DATA(obj->descriptor_config).srcYincrement = cfg->src_increment * cfg->burst_size;
786 GET_RESOURCE_DATA(obj->descriptor_config).dstYincrement = cfg->dst_increment * cfg->burst_size;
787 #endif
788
789 }
790 else
791 {
792 #if defined(CY_IP_MXSAXIDMAC)
793 GET_RESOURCE_DATA(obj->descriptor_config).descriptorType = CY_AXIDMAC_1D_MEMORY_COPY;
794 GET_RESOURCE_DATA(obj->descriptor_config).mCount = total_length;
795 #else
796 GET_RESOURCE_DATA(obj->descriptor_config).descriptorType = CY_DMAC_1D_TRANSFER;
797 GET_RESOURCE_DATA(obj->descriptor_config).xCount = total_length;
798 #endif
799 }
800
801 /* If burst action, configure trigger and interrupt actions */
802 if (cfg->burst_size != 0 &&
803 (cfg->action == CYHAL_DMA_TRANSFER_BURST || cfg->action == CYHAL_DMA_TRANSFER_BURST_DISABLE))
804 {
805 #if defined(CY_IP_MXSAXIDMAC)
806 obj->expected_bursts = GET_RESOURCE_DATA(obj->descriptor_config).xCount;
807 GET_RESOURCE_DATA(obj->descriptor_config).interruptType = _CYHAL_DMAC_M_LOOP;
808 if (obj->source == _CYHAL_TRIGGER_CPUSS_ZERO) // If not overridden by connect_digital()
809 GET_RESOURCE_DATA(obj->descriptor_config).triggerInType = _CYHAL_DMAC_M_LOOP;
810 #else
811 obj->expected_bursts = GET_RESOURCE_DATA(obj->descriptor_config).yCount;
812 GET_RESOURCE_DATA(obj->descriptor_config).interruptType = _CYHAL_DMAC_X_LOOP;
813 if (obj->source == _CYHAL_TRIGGER_CPUSS_ZERO) // If not overridden by connect_digital()
814 GET_RESOURCE_DATA(obj->descriptor_config).triggerInType = _CYHAL_DMAC_X_LOOP;
815 #endif
816 }
817 else
818 {
819 obj->expected_bursts = 1;
820 GET_RESOURCE_DATA(obj->descriptor_config).interruptType = _CYHAL_DMAC_DESCR;
821 if (obj->source == _CYHAL_TRIGGER_CPUSS_ZERO) // If not overridden by connect_digital()
822 GET_RESOURCE_DATA(obj->descriptor_config).triggerInType = _CYHAL_DMAC_DESCR;
823 }
824 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
825 if(cfg->burst_size != 0)
826 {
827 return CYHAL_DMA_RSLT_ERR_INVALID_BURST_SIZE;
828 }
829 else
830 {
831 GET_RESOURCE_DATA(obj->descriptor_config).dataCount = total_length;
832 GET_RESOURCE_DATA(obj->descriptor_config).srcAddrIncrement = cfg->src_increment;
833 GET_RESOURCE_DATA(obj->descriptor_config).dstAddrIncrement = cfg->dst_increment;
834 obj->expected_bursts = 1;
835 }
836 #endif
837
838 return _cyhal_dma_dmac_stage(obj);
839 }
840
_cyhal_dma_dmac_enable(cyhal_dma_t * obj)841 cy_rslt_t _cyhal_dma_dmac_enable(cyhal_dma_t *obj)
842 {
843 cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
844 _cyhal_dmac_channel_enable(base, obj->resource.channel_num);
845 return CY_RSLT_SUCCESS;
846 }
847
_cyhal_dma_dmac_disable(cyhal_dma_t * obj)848 cy_rslt_t _cyhal_dma_dmac_disable(cyhal_dma_t *obj)
849 {
850 cyhal_dmac_hw_type* base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
851 _cyhal_dmac_channel_disable(base, obj->resource.channel_num);
852 return CY_RSLT_SUCCESS;
853 }
854
_cyhal_dma_dmac_start_transfer(cyhal_dma_t * obj)855 cy_rslt_t _cyhal_dma_dmac_start_transfer(cyhal_dma_t *obj)
856 {
857 /* Return warning if channel is busy */
858 if(_cyhal_dma_dmac_is_busy(obj))
859 return CYHAL_DMA_RSLT_WARN_TRANSFER_ALREADY_STARTED;
860
861 if (_cyhal_dma_dmac_pm_transition_pending)
862 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
863
864 uint32_t trigline = _cyhal_dma_dmac_get_trigger_line(obj->resource.block_num, obj->resource.channel_num);
865 cy_en_trigmux_status_t trig_status = Cy_TrigMux_SwTrigger(trigline, CY_TRIGGER_TWO_CYCLES);
866
867 /* Also return warning if SW trigger is already initiated but DMA hardware
868 * has not seen it yet */
869 if(trig_status == CY_TRIGMUX_INVALID_STATE)
870 return CYHAL_DMA_RSLT_WARN_TRANSFER_ALREADY_STARTED;
871 else
872 return CY_RSLT_SUCCESS;
873 }
874
_cyhal_dma_dmac_enable_event(cyhal_dma_t * obj,cyhal_dma_event_t event,uint8_t intr_priority,bool enable)875 void _cyhal_dma_dmac_enable_event(cyhal_dma_t *obj, cyhal_dma_event_t event, uint8_t intr_priority, bool enable)
876 {
877 #if defined (CY_IP_M0S8CPUSSV3_DMAC)
878 DMAC_Type *base = _cyhal_dma_dmac_get_base(obj->resource.block_num);
879 uint32_t mask = Cy_DMAC_GetInterruptMask(base);
880 #endif
881 if(enable)
882 {
883 #if defined (CY_IP_M0S8CPUSSV3_DMAC)
884 Cy_DMAC_SetInterruptMask(base, mask | (1 << obj->resource.channel_num));
885 #endif
886 obj->irq_cause |= event;
887 }
888 else
889 {
890 #if defined (CY_IP_M0S8CPUSSV3_DMAC)
891 Cy_DMAC_SetInterruptMask(base, mask & ~(1 << obj->resource.channel_num));
892 #endif
893 obj->irq_cause &= ~event;
894 }
895
896 _cyhal_irq_set_priority(_cyhal_dma_dmac_get_irqn(obj), intr_priority);
897 }
898
_cyhal_dma_dmac_is_busy(cyhal_dma_t * obj)899 bool _cyhal_dma_dmac_is_busy(cyhal_dma_t *obj)
900 {
901 /* The value is a bit field of all pending or active channels */
902 return _cyhal_dmac_get_active_channel(_cyhal_dma_dmac_get_base(obj->resource.block_num)) & (1 << obj->resource.channel_num);
903 }
904 #if defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) || defined(CY_IP_MXSAXIDMAC)
905 #if defined(CY_IP_MXSAXIDMAC)
_cyhal_convert_input_t(cyhal_dma_input_t input)906 static cy_en_axidmac_trigger_type_t _cyhal_convert_input_t(cyhal_dma_input_t input)
907 {
908 switch(input)
909 {
910 case CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT:
911 return CY_AXIDMAC_M_LOOP;
912 case CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST:
913 return CY_AXIDMAC_X_LOOP;
914 case CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS:
915 return CY_AXIDMAC_DESCR;
916 default:
917 // Should never reach here. Just silencing compiler warnings.
918 CY_ASSERT(false);
919 return CY_AXIDMAC_DESCR;
920 }
921 }
922 #elif defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC)
_cyhal_convert_input_t(cyhal_dma_input_t input)923 static cy_en_dmac_trigger_type_t _cyhal_convert_input_t(cyhal_dma_input_t input)
924 {
925 switch(input)
926 {
927 case CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT:
928 return CY_DMAC_1ELEMENT;
929 case CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST:
930 return CY_DMAC_X_LOOP;
931 case CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS:
932 return CY_DMAC_DESCR;
933 default:
934 // Should never reach here. Just silencing compiler warnings.
935 CY_ASSERT(false);
936 return CY_DMAC_DESCR;
937 }
938 }
939 #endif
940
941 #if defined(CY_IP_MXSAXIDMAC)
_cyhal_convert_output_t(cyhal_dma_output_t output)942 static cy_en_axidmac_trigger_type_t _cyhal_convert_output_t(cyhal_dma_output_t output)
943 {
944 switch(output)
945 {
946 case CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT:
947 return CY_AXIDMAC_M_LOOP;
948 case CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST:
949 return CY_AXIDMAC_X_LOOP;
950 case CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS:
951 return CY_AXIDMAC_DESCR;
952 default:
953 // Should never reach here. Just silencing compiler warnings.
954 CY_ASSERT(false);
955 return CY_AXIDMAC_DESCR;
956 }
957 }
958 #else
_cyhal_convert_output_t(cyhal_dma_output_t output)959 static cy_en_dmac_trigger_type_t _cyhal_convert_output_t(cyhal_dma_output_t output)
960 {
961 switch(output)
962 {
963 case CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT:
964 return CY_DMAC_1ELEMENT;
965 case CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST:
966 return CY_DMAC_X_LOOP;
967 case CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS:
968 return CY_DMAC_DESCR;
969 default:
970 // Should never reach here. Just silencing compiler warnings.
971 CY_ASSERT(false);
972 return CY_DMAC_DESCR;
973 }
974 }
975 #endif
976
_cyhal_dma_dmac_connect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)977 cy_rslt_t _cyhal_dma_dmac_connect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
978 {
979 if(input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT &&
980 input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST &&
981 input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS)
982 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
983
984 obj->descriptor_config.dmac.triggerInType = _cyhal_convert_input_t(input);
985
986 _cyhal_dmac_channel_disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
987
988 obj->descriptor.dmac.ctl &= ~_CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Msk;
989 obj->descriptor.dmac.ctl |= _VAL2FLD(_CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE, obj->descriptor_config.dmac.triggerInType);
990
991 _cyhal_dmac_channel_enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
992
993 cyhal_dest_t dest = _cyhal_dma_dmac_get_dest(obj->resource.block_num, obj->resource.channel_num);
994
995 return _cyhal_connect_signal(source, dest);
996 }
997
_cyhal_dma_dmac_enable_output(cyhal_dma_t * obj,cyhal_dma_output_t output,cyhal_source_t * source)998 cy_rslt_t _cyhal_dma_dmac_enable_output(cyhal_dma_t *obj, cyhal_dma_output_t output, cyhal_source_t *source)
999 {
1000 if(output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT &&
1001 output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST &&
1002 output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS)
1003 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1004
1005 _cyhal_dmac_channel_disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
1006
1007 obj->descriptor.dmac.ctl &= ~_CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Msk;
1008 obj->descriptor.dmac.ctl |= _VAL2FLD(_CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE, _cyhal_convert_output_t(output));
1009
1010 _cyhal_dmac_channel_enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
1011 *source = _cyhal_dma_dmac_get_src(obj->resource.block_num, obj->resource.channel_num);
1012
1013 return CY_RSLT_SUCCESS;
1014 }
1015
_cyhal_dma_dmac_disconnect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)1016 cy_rslt_t _cyhal_dma_dmac_disconnect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
1017 {
1018 if(input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT &&
1019 input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_BURST &&
1020 input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS)
1021 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1022
1023
1024 // There is no option to totally disable. Just reset to default.
1025 // NOTE: Use .interruptType since it matches the desired .triggerInType from configure(), but
1026 // is not modified by connect/disconnect functions
1027 _cyhal_dmac_channel_disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
1028
1029 obj->descriptor.dmac.ctl &= ~_CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE_Msk;
1030 obj->descriptor.dmac.ctl |= _VAL2FLD(_CYHAL_DMAC_CH_DESCR_CTL_TR_IN_TYPE, _cyhal_dma_dmac_default_descriptor_config.interruptType);
1031
1032 _cyhal_dmac_channel_enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
1033
1034 cyhal_dest_t dest = _cyhal_dma_dmac_get_dest(obj->resource.block_num, obj->resource.channel_num);
1035
1036 return _cyhal_disconnect_signal(source, dest);
1037 }
1038
_cyhal_dma_dmac_disable_output(cyhal_dma_t * obj,cyhal_dma_output_t output)1039 cy_rslt_t _cyhal_dma_dmac_disable_output(cyhal_dma_t *obj, cyhal_dma_output_t output)
1040 {
1041 if(output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT &&
1042 output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_BURST &&
1043 output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS)
1044 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1045
1046 // There is no option to totally disable. Just reset to default.
1047 _cyhal_dmac_channel_disable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
1048
1049 obj->descriptor.dmac.ctl &= ~_CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE_Msk;
1050 obj->descriptor.dmac.ctl |= _VAL2FLD(_CYHAL_DMAC_CH_DESCR_CTL_TR_OUT_TYPE, _cyhal_dma_dmac_default_descriptor_config.triggerOutType);
1051
1052 _cyhal_dmac_channel_enable(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num);
1053
1054 return CY_RSLT_SUCCESS;
1055
1056 }
1057 #elif defined(CY_IP_M0S8CPUSSV3_DMAC)
1058
_cyhal_dma_dmac_connect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)1059 cy_rslt_t _cyhal_dma_dmac_connect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
1060 {
1061 if((input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT) &&
1062 (input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS))
1063 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1064
1065 Cy_DMAC_Channel_SetCurrentDescriptor(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num, obj->descriptor);
1066
1067 cyhal_dest_t dest = (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + obj->resource.channel_num);
1068
1069
1070 return _cyhal_connect_signal(source, dest);
1071 }
1072
1073 // 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)1074 cy_rslt_t _cyhal_dma_dmac_enable_output(cyhal_dma_t *obj, cyhal_dma_output_t output, cyhal_source_t *source)
1075 {
1076 if((output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT) &&
1077 (output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS))
1078 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1079
1080 *source = _cyhal_dma_dmac_get_src(obj->resource.block_num, obj->resource.channel_num);
1081
1082 return CY_RSLT_SUCCESS;
1083 }
1084
_cyhal_dma_dmac_disconnect_digital(cyhal_dma_t * obj,cyhal_source_t source,cyhal_dma_input_t input)1085 cy_rslt_t _cyhal_dma_dmac_disconnect_digital(cyhal_dma_t *obj, cyhal_source_t source, cyhal_dma_input_t input)
1086 {
1087 if((input != CYHAL_DMA_INPUT_TRIGGER_SINGLE_ELEMENT) &&
1088 (input != CYHAL_DMA_INPUT_TRIGGER_ALL_ELEMENTS))
1089 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1090
1091 // Reset to default
1092 Cy_DMAC_Channel_SetCurrentDescriptor(_cyhal_dma_dmac_get_base(obj->resource.block_num), obj->resource.channel_num, obj->descriptor);
1093
1094 cyhal_dest_t dest = (cyhal_dest_t)(CYHAL_TRIGGER_CPUSS_DMAC0_TR_IN0 + obj->resource.channel_num);
1095
1096 return _cyhal_disconnect_signal(source, dest);
1097 }
1098
1099 // M0S8 output triggers are always active. This is a noop.
_cyhal_dma_dmac_disable_output(cyhal_dma_t * obj,cyhal_dma_output_t output)1100 cy_rslt_t _cyhal_dma_dmac_disable_output(cyhal_dma_t *obj, cyhal_dma_output_t output)
1101 {
1102 CY_UNUSED_PARAMETER(obj);
1103
1104 if((output != CYHAL_DMA_OUTPUT_TRIGGER_SINGLE_ELEMENT) &&
1105 (output != CYHAL_DMA_OUTPUT_TRIGGER_ALL_ELEMENTS))
1106 return CYHAL_DMA_RSLT_ERR_INVALID_PARAMETER;
1107
1108 return CY_RSLT_SUCCESS;
1109 }
1110
1111 #endif /* defined(CY_IP_M4CPUSS_DMAC) || defined(CY_IP_M7CPUSS_DMAC) || defined(CY_IP_MXAHBDMAC) */
1112
1113 #endif /* (_CYHAL_DRIVER_AVAILABLE_DMA_DMAC) */
1114
1115 #if defined(__cplusplus)
1116 }
1117 #endif
1118