1 /***************************************************************************//**
2 * \file cy_dmac.c
3 * \version 1.20
4 *
5 * \brief
6 * The source code file for the DMAC driver.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2020 Cypress Semiconductor Corporation
11 * SPDX-License-Identifier: Apache-2.0
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *******************************************************************************/
25
26 #include "cy_device.h"
27
28 #if defined (CY_IP_M4CPUSS_DMAC) || defined (CY_IP_MXAHBDMAC)
29
30 #include "cy_dmac.h"
31
32 CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 11.3', 8, \
33 'The cast to another type is made intentionally. \
34 These structures are subset of the main structure cy_stc_dmac_descriptor_t. \
35 This will provide better code readability with the type of data transfer used');
36
37 CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 10.8', 2, \
38 'Value extracted from _VAL2FLD macro will not exceed enum range.');
39
40 /*******************************************************************************
41 * Function Name: Cy_DMAC_Descriptor_Init
42 ****************************************************************************//**
43 *
44 * Initializes the descriptor structure in SRAM from a pre-initialized
45 * configuration structure.
46 * This function initializes only the descriptor and not the channel.
47 *
48 * \param descriptor
49 * The descriptor structure instance.
50 *
51 * \param config
52 * This is a configuration structure that has all initialization information for
53 * the descriptor.
54 *
55 * \return
56 * The status /ref cy_en_dmac_status_t.
57 *
58 * \funcusage
59 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Enable
60 *
61 *******************************************************************************/
Cy_DMAC_Descriptor_Init(cy_stc_dmac_descriptor_t * descriptor,const cy_stc_dmac_descriptor_config_t * config)62 cy_en_dmac_status_t Cy_DMAC_Descriptor_Init(cy_stc_dmac_descriptor_t * descriptor, const cy_stc_dmac_descriptor_config_t * config)
63 {
64 cy_en_dmac_status_t ret = CY_DMAC_BAD_PARAM;
65
66 if ((NULL != descriptor) && (NULL != config))
67 {
68 CY_ASSERT_L3(CY_DMAC_IS_RETRIGGER_VALID(config->retrigger));
69 CY_ASSERT_L3(CY_DMAC_IS_TRIG_TYPE_VALID(config->interruptType));
70 CY_ASSERT_L3(CY_DMAC_IS_TRIG_TYPE_VALID(config->triggerOutType));
71 CY_ASSERT_L3(CY_DMAC_IS_TRIG_TYPE_VALID(config->triggerInType));
72 CY_ASSERT_L3(CY_DMAC_IS_XFER_SIZE_VALID(config->srcTransferSize));
73 CY_ASSERT_L3(CY_DMAC_IS_XFER_SIZE_VALID(config->dstTransferSize));
74 CY_ASSERT_L3(CY_DMAC_IS_CHANNEL_STATE_VALID(config->channelState));
75 CY_ASSERT_L3(CY_DMAC_IS_DATA_SIZE_VALID(config->dataSize));
76 CY_ASSERT_L3(CY_DMAC_IS_TYPE_VALID(config->descriptorType));
77
78 descriptor->ctl =
79 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_WAIT_FOR_DEACT, config->retrigger) |
80 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_INTR_TYPE, config->interruptType) |
81 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_TR_OUT_TYPE, config->triggerOutType) |
82 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_TR_IN_TYPE, config->triggerInType) |
83 _BOOL2FLD(DMAC_CH_V2_DESCR_CTL_DATA_PREFETCH, config->dataPrefetch) |
84 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_SRC_TRANSFER_SIZE, config->srcTransferSize) |
85 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_DST_TRANSFER_SIZE, config->dstTransferSize) |
86 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_CH_DISABLE, config->channelState) |
87 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_DATA_SIZE, config->dataSize) |
88 _VAL2FLD(DMAC_CH_V2_DESCR_CTL_DESCR_TYPE, config->descriptorType);
89
90 descriptor->src = (uint32_t)config->srcAddress;
91
92 if(CY_DMAC_SCATTER_TRANSFER != config->descriptorType)
93 {
94 Cy_DMAC_Descriptor_SetDstAddress(descriptor, config->dstAddress);
95 }
96
97 if(CY_DMAC_SINGLE_TRANSFER != config->descriptorType)
98 {
99 Cy_DMAC_Descriptor_SetXloopDataCount(descriptor, config->xCount);
100 }
101
102 Cy_DMAC_Descriptor_SetNextDescriptor(descriptor, config->nextDescriptor);
103
104 if((CY_DMAC_1D_TRANSFER == config->descriptorType) ||
105 (CY_DMAC_2D_TRANSFER == config->descriptorType))
106 {
107 CY_ASSERT_L2(CY_DMAC_IS_LOOP_INCR_VALID(config->srcXincrement));
108 CY_ASSERT_L2(CY_DMAC_IS_LOOP_INCR_VALID(config->dstXincrement));
109
110 descriptor->xIncr = _VAL2FLD(DMAC_CH_V2_DESCR_X_INCR_SRC_X, config->srcXincrement) |
111 _VAL2FLD(DMAC_CH_V2_DESCR_X_INCR_DST_X, config->dstXincrement);
112 }
113
114 if(CY_DMAC_2D_TRANSFER == config->descriptorType)
115 {
116 Cy_DMAC_Descriptor_SetYloopDataCount(descriptor, config->yCount);
117
118 CY_ASSERT_L2(CY_DMAC_IS_LOOP_INCR_VALID(config->srcYincrement));
119 CY_ASSERT_L2(CY_DMAC_IS_LOOP_INCR_VALID(config->dstYincrement));
120
121 descriptor->yIncr = _VAL2FLD(DMAC_CH_V2_DESCR_Y_INCR_SRC_Y, config->srcYincrement) |
122 _VAL2FLD(DMAC_CH_V2_DESCR_Y_INCR_DST_Y, config->dstYincrement);
123 }
124
125 ret = CY_DMAC_SUCCESS;
126 }
127
128 return ret;
129 }
130
131
132 /*******************************************************************************
133 * Function Name: Cy_DMAC_Descriptor_DeInit
134 ****************************************************************************//**
135 *
136 * Clears the content of the specified descriptor.
137 *
138 * \param descriptor
139 * The descriptor structure instance.
140 *
141 * \funcusage
142 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Descriptor_Deinit
143 *
144 *******************************************************************************/
Cy_DMAC_Descriptor_DeInit(cy_stc_dmac_descriptor_t * descriptor)145 void Cy_DMAC_Descriptor_DeInit(cy_stc_dmac_descriptor_t * descriptor)
146 {
147 descriptor->ctl = 0UL;
148 descriptor->src = 0UL;
149 descriptor->dst = 0UL;
150 descriptor->xSize = 0UL;
151 descriptor->xIncr = 0UL;
152 descriptor->ySize = 0UL;
153 descriptor->yIncr = 0UL;
154 descriptor->nextPtr = 0UL;
155 }
156
157
158 /*******************************************************************************
159 * Function Name: Cy_DMAC_Channel_Init
160 ****************************************************************************//**
161 *
162 * Initializes the DMAC channel with a descriptor and other parameters.
163 *
164 * \param base
165 * The pointer to the hardware DMAC block.
166 *
167 * \param channel
168 * A channel number.
169 *
170 * \param config
171 * The structure that has the initialization information for the
172 * channel.
173 *
174 * \return
175 * The status /ref cy_en_dmac_status_t.
176 *
177 * \funcusage
178 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Enable
179 *
180 *******************************************************************************/
Cy_DMAC_Channel_Init(DMAC_Type * base,uint32_t channel,cy_stc_dmac_channel_config_t const * config)181 cy_en_dmac_status_t Cy_DMAC_Channel_Init(DMAC_Type * base, uint32_t channel, cy_stc_dmac_channel_config_t const * config)
182 {
183 cy_en_dmac_status_t ret = CY_DMAC_BAD_PARAM;
184
185 if ((NULL != base) && (CY_DMAC_IS_CH_NR_VALID(channel)) && (NULL != config) && (NULL != config->descriptor))
186 {
187 CY_ASSERT_L2(CY_DMAC_IS_PRIORITY_VALID(config->priority));
188
189 /* Set the current descriptor */
190 DMAC_CH_CURR(base, channel) = (uint32_t)config->descriptor;
191
192 /* Set the channel configuration */
193 DMAC_CH_CTL(base, channel) = _VAL2FLD(DMAC_CH_V2_CTL_PRIO, config->priority) |
194 _BOOL2FLD(DMAC_CH_V2_CTL_ENABLED, config->enable) |
195 _BOOL2FLD(DMAC_CH_V2_CTL_B, config->bufferable);
196 ret = CY_DMAC_SUCCESS;
197 }
198
199 return (ret);
200 }
201
202
203 /*******************************************************************************
204 * Function Name: Cy_DMAC_Channel_DeInit
205 ****************************************************************************//**
206 *
207 * Clears the content of registers corresponding to the channel.
208 *
209 * \param base
210 * The pointer to the hardware DMAC block.
211 *
212 * \param channel
213 * A channel number.
214 *
215 * \funcusage
216 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Disable
217 *
218 *******************************************************************************/
Cy_DMAC_Channel_DeInit(DMAC_Type * base,uint32_t channel)219 void Cy_DMAC_Channel_DeInit(DMAC_Type * base, uint32_t channel)
220 {
221 CY_ASSERT_L1(CY_DMAC_IS_CH_NR_VALID(channel));
222
223 DMAC_CH_CTL(base, channel) = 0UL;
224 DMAC_CH_CURR(base, channel) = 0UL;
225 DMAC_CH_INTR_MASK(base, channel) = 0UL;
226 }
227
228
229 /*******************************************************************************
230 * Function Name: Cy_DMAC_Descriptor_GetXloopDataCount
231 ****************************************************************************//**
232 *
233 * Returns the number of data elements for the X loop of the specified
234 * descriptor (for all descriptor types except single transfer).
235 *
236 * Based on the descriptor type, the offset of the address for the xCount
237 * register may vary:
238 * For the scatter transfer descriptors type, this register is at offset 0x8.
239 * For all the rest supported descriptor types, this register is at offset 0xc.
240 *
241 * \param descriptor
242 * The descriptor structure instance.
243 *
244 * \return
245 * The number of data elements to transfer in the X loop.
246 * For scatter transfer descriptors the X loop count unit is
247 * an [address, data] pair (two words, or 8 bytes).
248 * For memory copy descriptors X loop count unit is one byte.
249 * For all the rest descriptors (except single transfer) the X loop count unit
250 * is specified by the data transfer size /ref cy_en_dmac_data_size_t.
251 *
252 * \funcusage
253 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Descriptor_GetterFunctions
254 *
255 *******************************************************************************/
Cy_DMAC_Descriptor_GetXloopDataCount(cy_stc_dmac_descriptor_t const * descriptor)256 uint32_t Cy_DMAC_Descriptor_GetXloopDataCount(cy_stc_dmac_descriptor_t const * descriptor)
257 {
258 uint32_t retVal = 0UL;
259 cy_en_dmac_descriptor_type_t locDescriptorType = Cy_DMAC_Descriptor_GetDescriptorType(descriptor);
260
261 CY_ASSERT_L1(CY_DMAC_SINGLE_TRANSFER != locDescriptorType);
262
263 if (CY_DMAC_SCATTER_TRANSFER == locDescriptorType)
264 {
265 /* Convert the data count from the machine range (0-65535) into the user's range (1-32768). */
266 retVal = (_FLD2VAL(DMAC_CH_V2_DESCR_X_SIZE_X_COUNT, ((cy_stc_dmac_dscr_scatter_t const*)descriptor)->xSize) + 1UL) / 2UL;
267 }
268 else
269 {
270 /* Convert the data count from the machine range (0-65535) into the user's range (1-65536). */
271 retVal = _FLD2VAL(DMAC_CH_V2_DESCR_X_SIZE_X_COUNT, descriptor->xSize) + 1UL;
272 }
273
274 return (retVal);
275 }
276
277
278 /*******************************************************************************
279 * Function Name: Cy_DMAC_Descriptor_SetXloopDataCount
280 ****************************************************************************//**
281 *
282 * Sets the number of data elements to transfer in the X loop
283 * for the specified descriptor (for all descriptor types except single transfer).
284 *
285 * Based on the descriptor type, the offset of the address for the xCount
286 * register may vary:
287 * For the scatter transfer descriptors type, this register is at offset 0x8.
288 * For all the rest of the supported descriptor types, this register is at offset 0xc.
289 *
290 * \param descriptor
291 * The descriptor structure instance.
292 *
293 * \param xCount
294 * The number of data elements to transfer in the X loop.
295 * For scatter transfer descriptors the valid range is 1...32768.
296 * For all the rest of the descriptors (except single transfer), the valid range is 1...65536.
297 *
298 * \funcusage
299 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Descriptor_SetterFunctions
300 *
301 *******************************************************************************/
Cy_DMAC_Descriptor_SetXloopDataCount(cy_stc_dmac_descriptor_t * descriptor,uint32_t xCount)302 void Cy_DMAC_Descriptor_SetXloopDataCount(cy_stc_dmac_descriptor_t * descriptor, uint32_t xCount)
303 {
304 cy_en_dmac_descriptor_type_t locDescriptorType = Cy_DMAC_Descriptor_GetDescriptorType(descriptor);
305
306 CY_ASSERT_L1(CY_DMAC_SINGLE_TRANSFER != locDescriptorType);
307
308 if (CY_DMAC_SCATTER_TRANSFER == locDescriptorType)
309 {
310 CY_ASSERT_L2(CY_DMAC_IS_SCATTER_COUNT_VALID(xCount));
311 /* Convert the data count from the user's range (1-32768) into the machine range (0-65535). */
312 ((cy_stc_dmac_dscr_scatter_t*)descriptor)->xSize = _VAL2FLD(DMAC_CH_V2_DESCR_X_SIZE_X_COUNT, (xCount * 2UL) - 1UL);
313 }
314 else
315 {
316 CY_ASSERT_L2(CY_DMAC_IS_LOOP_COUNT_VALID(xCount));
317 /* Convert the data count from the user's range (1-65536) into the machine range (0-65535). */
318 descriptor->xSize = _VAL2FLD(DMAC_CH_V2_DESCR_X_SIZE_X_COUNT, xCount - 1UL);
319 }
320 }
321
322
323 /*******************************************************************************
324 * Function Name: Cy_DMAC_Descriptor_SetNextDescriptor
325 ****************************************************************************//**
326 *
327 * Sets a Next Descriptor parameter for the specified descriptor.
328 *
329 * Based on the descriptor type, the offset of the address for the next descriptor
330 * register may vary:
331 * For the single and scatter transfer descriptors, this register is at offset 0x0c.
332 * For the memory copy descriptor type, this register is at offset 0x10.
333 * For the 1D-transfer descriptor type, this register is at offset 0x14.
334 * For the 2D-transfer descriptor type, this register is at offset 0x1c.
335 *
336 * \param descriptor
337 * The descriptor structure instance.
338 *
339 * \param nextDescriptor
340 * The pointer to the next descriptor.
341 *
342 * \funcusage
343 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Descriptor_SetterFunctions
344 *
345 *******************************************************************************/
Cy_DMAC_Descriptor_SetNextDescriptor(cy_stc_dmac_descriptor_t * descriptor,cy_stc_dmac_descriptor_t const * nextDescriptor)346 void Cy_DMAC_Descriptor_SetNextDescriptor(cy_stc_dmac_descriptor_t * descriptor, cy_stc_dmac_descriptor_t const * nextDescriptor)
347 {
348 CY_ASSERT_L1(NULL != descriptor);
349
350 switch((cy_en_dmac_descriptor_type_t)_FLD2VAL(DMAC_CH_V2_DESCR_CTL_DESCR_TYPE, descriptor->ctl))
351 {
352 case CY_DMAC_SINGLE_TRANSFER:
353 case CY_DMAC_SCATTER_TRANSFER:
354 /* The next pointer is on the same offset for single and scatter descriptors */
355 ((cy_stc_dmac_dscr_single_t*)descriptor)->nextPtr = (uint32_t)nextDescriptor;
356 break;
357
358 case CY_DMAC_MEMORY_COPY:
359 ((cy_stc_dmac_dscr_memcpy_t*)descriptor)->nextPtr = (uint32_t)nextDescriptor;
360 break;
361
362 case CY_DMAC_1D_TRANSFER:
363 ((cy_stc_dmac_dscr_1d_t*)descriptor)->nextPtr = (uint32_t)nextDescriptor;
364 break;
365
366 case CY_DMAC_2D_TRANSFER:
367 ((cy_stc_dmac_dscr_2d_t*)descriptor)->nextPtr = (uint32_t)nextDescriptor;
368 break;
369
370 default:
371 /* Unsupported type of descriptor */
372 break;
373 }
374 }
375
376
377 /*******************************************************************************
378 * Function Name: Cy_DMAC_Descriptor_GetNextDescriptor
379 ****************************************************************************//**
380 *
381 * Returns a next descriptor address of the specified descriptor.
382 *
383 * Based on the descriptor type, the offset of the address for the next descriptor
384 * register may vary:
385 * For the single and scatter transfer descriptors, this register is at offset 0x0c.
386 * For the memory copy descriptor type, this register is at offset 0x10.
387 * For the 1D-transfer descriptor type, this register is at offset 0x14.
388 * For the 2D-transfer descriptor type, this register is at offset 0x1c.
389 *
390 * \param descriptor
391 * The descriptor structure instance.
392 *
393 * \return
394 * The pointer to the next descriptor.
395 *
396 * \funcusage
397 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Descriptor_GetterFunctions
398 *
399 *******************************************************************************/
Cy_DMAC_Descriptor_GetNextDescriptor(cy_stc_dmac_descriptor_t const * descriptor)400 cy_stc_dmac_descriptor_t * Cy_DMAC_Descriptor_GetNextDescriptor(cy_stc_dmac_descriptor_t const * descriptor)
401 {
402 uint32_t retVal = 0UL;
403
404 switch((cy_en_dmac_descriptor_type_t)_FLD2VAL(DMAC_CH_V2_DESCR_CTL_DESCR_TYPE, descriptor->ctl))
405 {
406 case CY_DMAC_SINGLE_TRANSFER:
407 case CY_DMAC_SCATTER_TRANSFER:
408 /* The next pointer is on the same offset for single and scatter descriptors */
409 retVal = ((cy_stc_dmac_dscr_single_t const*)descriptor)->nextPtr;
410 break;
411
412 case CY_DMAC_MEMORY_COPY:
413 retVal = ((cy_stc_dmac_dscr_memcpy_t const*)descriptor)->nextPtr;
414 break;
415
416 case CY_DMAC_1D_TRANSFER:
417 retVal = ((cy_stc_dmac_dscr_1d_t const*)descriptor)->nextPtr;
418 break;
419
420 case CY_DMAC_2D_TRANSFER:
421 retVal = ((cy_stc_dmac_dscr_2d_t const*)descriptor)->nextPtr;
422 break;
423
424 default:
425 /* An unsupported type of the descriptor */
426 break;
427 }
428
429 return ((cy_stc_dmac_descriptor_t*)retVal);
430 }
431
432
433 /*******************************************************************************
434 * Function Name: Cy_DMAC_Descriptor_SetDescriptorType
435 ****************************************************************************//**
436 *
437 * Sets the descriptor's type for the specified descriptor.
438 * Moves the next descriptor pointer and X data count values into the proper
439 * offset in accordance to the actual descriptor type.
440 *
441 * During the descriptor's type change, carefully set up the settings starting
442 * from dstAddress and all the rest below in the \ref cy_stc_dmac_descriptor_config_t
443 * structure. This is because the content of the descriptor registers might be
444 * lost/overridden by other descriptor settings due to the
445 * different registers structure for different descriptor types.
446 *
447 * \param descriptor
448 * The descriptor structure instance.
449 *
450 * \param descriptorType
451 * The descriptor type \ref cy_en_dmac_descriptor_type_t.
452 *
453 * \funcusage
454 * \snippet dmac/snippet/main.c snippet_Cy_DMAC_Descriptor_SetterFunctions
455 *
456 *******************************************************************************/
Cy_DMAC_Descriptor_SetDescriptorType(cy_stc_dmac_descriptor_t * descriptor,cy_en_dmac_descriptor_type_t descriptorType)457 void Cy_DMAC_Descriptor_SetDescriptorType(cy_stc_dmac_descriptor_t * descriptor, cy_en_dmac_descriptor_type_t descriptorType)
458 {
459 CY_ASSERT_L3(CY_DMAC_IS_TYPE_VALID(descriptorType));
460
461 if (descriptorType != Cy_DMAC_Descriptor_GetDescriptorType(descriptor)) /* Do not perform if the type is not changed */
462 {
463 /* Store the current nextDescriptor pointer. */
464 cy_stc_dmac_descriptor_t const *locNextDescriptor = Cy_DMAC_Descriptor_GetNextDescriptor(descriptor);
465 /* Store the current X data counter. */
466 uint32_t locXcount = Cy_DMAC_Descriptor_GetXloopDataCount(descriptor);
467 /* Change the descriptor type. */
468 CY_REG32_CLR_SET(descriptor->ctl, DMAC_CH_V2_DESCR_CTL_DESCR_TYPE, descriptorType);
469 /* Restore the current X data counter. */
470 Cy_DMAC_Descriptor_SetXloopDataCount(descriptor, locXcount);
471 /* Restore the nextDescriptor pointer into the proper place. */
472 Cy_DMAC_Descriptor_SetNextDescriptor(descriptor, locNextDescriptor);
473 }
474 }
475
476 CY_MISRA_BLOCK_END('MISRA C-2012 Rule 11.3');
477 CY_MISRA_BLOCK_END('MISRA C-2012 Rule 10.8');
478
479 #endif /* CY_IP_M4CPUSS_DMAC, CY_IP_MXAHBDMAC */
480
481 /* [] END OF FILE */
482