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