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