1 /***************************************************************************//**
2  * @file
3  * @brief Direct memory access (DMA) module peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_dma.h"
32 #if defined(DMA_PRESENT)
33 
34 #include "em_cmu.h"
35 #include "sl_assert.h"
36 #include "em_bus.h"
37 
38 /***************************************************************************//**
39  * @addtogroup dma DMA - Direct Memory Access
40  * @brief Direct Memory Access (DMA) Peripheral API
41  * @details
42  *  DMA access functions provide basic support for the following
43  *  types of DMA cycles:
44  *
45  *  @li @b Basic, used for transferring data between memory and peripherals.
46  *  @li @b Auto-request, used for transferring data between memory locations.
47  *  @li @b Ping-pong, used for for continuous transfer of data between memory
48  *    and peripherals, automatically toggling between primary and alternate
49  *    descriptors.
50  *  @li @b Memory @b scatter-gather, used for transferring a number of buffers
51  *    between memory locations.
52  *  @li @b Peripheral @b scatter-gather, used for transferring a number of
53  *    buffers between memory and peripherals.
54  *
55  *  A basic understanding of the DMA controller is assumed. See
56  *  the reference manual for more details.
57  *
58  *  The term 'descriptor' is synonymous to the 'channel control data
59  *  structure' term.
60  *
61  *  To use the DMA controller, the initialization function must have
62  *  been executed once (normally during the system initialization):
63  * @verbatim
64  * DMA_Init();
65  * @endverbatim
66  *
67  *  Normally, a DMA channel is configured:
68  * @verbatim
69  * DMA_CfgChannel();
70  * @endverbatim
71  *
72  *  The channel configuration only has to be done once if reusing the channel
73  *  for the same purpose later.
74  *
75  *  To set up a DMA cycle, the primary and/or alternate descriptor
76  *  has to be set up as indicated below.
77  *
78  *  For basic or auto-request cycles, use once on either primary or alternate
79  *  descriptor:
80  * @verbatim
81  * DMA_CfgDescr();
82  * @endverbatim
83  *
84  * For ping-pong cycles, configure both primary or alternate descriptors:
85  * @verbatim
86  * DMA_CfgDescr(); // Primary descriptor config
87  * DMA_CfgDescr(); // Alternate descriptor config
88  * @endverbatim
89  *
90  * For scatter-gather cycles, program the alternate descriptor array:
91  * @verbatim
92  * // 'n' is the number of scattered buffers
93  * // 'descr' points to the start of the alternate descriptor array
94  *
95  * // Fill in 'cfg'
96  * DMA_CfgDescrScatterGather(descr, 0, cfg);
97  * // Fill in 'cfg'
98  * DMA_CfgDescrScatterGather(descr, 1, cfg);
99  * :
100  * // Fill in 'cfg'
101  * DMA_CfgDescrScatterGather(descr, n - 1, cfg);
102  * @endverbatim
103  *
104  * In many cases, the descriptor configuration only has to be done once if
105  * re-using the channel for the same type of DMA cycles later.
106  *
107  * To activate the DMA cycle, use the respective DMA_Activate...()
108  * function.
109  *
110  * For ping-pong DMA cycles, use DMA_RefreshPingPong() from the callback to
111  * prepare the completed descriptor for reuse. Notice that the refresh must
112  * be done prior to the other active descriptor completes, otherwise the
113  * ping-pong DMA cycle will halt.
114  * @{
115  ******************************************************************************/
116 
117 /*******************************************************************************
118  **************************   LOCAL FUNCTIONS   ********************************
119  ******************************************************************************/
120 
121 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
122 
123 /***************************************************************************//**
124  * @brief
125  *   Prepare the descriptor for the DMA cycle.
126  *
127  * @details
128  *   This function prepares the last parts of the configuration required to start a
129  *   DMA cycle. Since the DMA controller itself modifies some parts of the
130  *   descriptor during use, those parts need to be refreshed if reusing a
131  *   descriptor configuration.
132  *
133  * @note
134  *   If using this function on a descriptor already activated and in use by the
135  *   DMA controller, the behavior is undefined.
136  *
137  * @param[in] channel
138  *   The DMA channel to prepare for the DMA cycle.
139  *
140  * @param[in] cycleCtrl
141  *   The DMA cycle type to prepare for.
142  *
143  * @param[in] primary
144  *   @li true - prepare the primary descriptor
145  *   @li false - prepare an alternate descriptor
146  *
147  * @param[in] useBurst
148  *   The burst feature is only used on peripherals supporting DMA bursts.
149  *   Bursts must not be used if the total length (as given by nMinus1) is
150  *   less than the arbitration rate configured for the descriptor.
151  *   See the reference manual for more details on burst usage.
152  *
153  * @param[in] dst
154  *   An address to a start location to transfer data to. If NULL, leave setting in
155  *   descriptor as is.
156  *
157  * @param[in] src
158  *   An address to a start location to transfer data from. If NULL, leave setting in
159  *   descriptor as is.
160  *
161  * @param[in] nMinus1
162  *   A number of elements (minus 1) to transfer (<= 1023).
163  ******************************************************************************/
DMA_Prepare(unsigned int channel,DMA_CycleCtrl_TypeDef cycleCtrl,bool primary,bool useBurst,void * dst,const void * src,unsigned int nMinus1)164 static void DMA_Prepare(unsigned int channel,
165                         DMA_CycleCtrl_TypeDef cycleCtrl,
166                         bool primary,
167                         bool useBurst,
168                         void *dst,
169                         const void *src,
170                         unsigned int nMinus1)
171 {
172   DMA_DESCRIPTOR_TypeDef *descr;
173   DMA_DESCRIPTOR_TypeDef *primDescr;
174   DMA_CB_TypeDef         *cb;
175   uint32_t               inc;
176   uint32_t               chBit;
177   uint32_t               tmp;
178 
179   primDescr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE)) + channel;
180 
181   /* Find a descriptor to configure. */
182   if (primary) {
183     descr = primDescr;
184   } else {
185     descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)) + channel;
186   }
187 
188   /* If callback is defined, update information on whether the callback is issued */
189   /* for primary or alternate descriptor. This is mainly needed for ping-pong */
190   /* cycles. */
191   cb = (DMA_CB_TypeDef *)(primDescr->USER);
192   if (cb) {
193     cb->primary = (uint8_t)primary;
194   }
195 
196   if (src) {
197     inc = (descr->CTRL & _DMA_CTRL_SRC_INC_MASK) >> _DMA_CTRL_SRC_INC_SHIFT;
198     if (inc == _DMA_CTRL_SRC_INC_NONE) {
199       descr->SRCEND = (volatile void*)src;
200     } else {
201       descr->SRCEND = (void *)((uint32_t)src + (nMinus1 << inc));
202     }
203   }
204 
205   if (dst) {
206     inc = (descr->CTRL & _DMA_CTRL_DST_INC_MASK) >> _DMA_CTRL_DST_INC_SHIFT;
207     if (inc == _DMA_CTRL_DST_INC_NONE) {
208       descr->DSTEND = dst;
209     } else {
210       descr->DSTEND = (void *)((uint32_t)dst + (nMinus1 << inc));
211     }
212   }
213 
214   chBit = 1 << channel;
215   if (useBurst) {
216     DMA->CHUSEBURSTS = chBit;
217   } else {
218     DMA->CHUSEBURSTC = chBit;
219   }
220 
221   if (primary) {
222     DMA->CHALTC = chBit;
223   } else {
224     DMA->CHALTS = chBit;
225   }
226 
227   /* Set the cycle control. */
228   tmp  = descr->CTRL & ~(_DMA_CTRL_CYCLE_CTRL_MASK | _DMA_CTRL_N_MINUS_1_MASK);
229   tmp |= nMinus1 << _DMA_CTRL_N_MINUS_1_SHIFT;
230   tmp |= (uint32_t)cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT;
231   descr->CTRL = tmp;
232 }
233 
234 /** @endcond */
235 
236 /*******************************************************************************
237  ************************   INTERRUPT FUNCTIONS   ******************************
238  ******************************************************************************/
239 
240 #ifndef EXCLUDE_DEFAULT_DMA_IRQ_HANDLER
241 
242 /***************************************************************************//**
243  * @brief
244  *   Interrupt handler for the DMA cycle completion handling.
245  *
246  * @details
247  *   Clears any pending flags and calls registered callback (if any).
248  *
249  *   If using the default interrupt vector table setup provided, this function
250  *   is automatically placed in the IRQ table due to weak linking. If taking
251  *   control over the interrupt vector table in some other way, this interrupt
252  *   handler must be installed to support callback actions.
253  *
254  *   For the user to implement a custom IRQ handler or run without
255  *   a DMA IRQ handler, define EXCLUDE_DEFAULT_DMA_IRQ_HANDLER
256  *   with a \#define statement or with the compiler option -D.
257  *
258  ******************************************************************************/
DMA_IRQHandler(void)259 void DMA_IRQHandler(void)
260 {
261   int                    channel;
262   DMA_CB_TypeDef         *cb;
263   uint32_t               pending;
264   uint32_t               pendingPrio;
265   uint32_t               prio;
266   uint32_t               primaryCpy;
267   int                    i;
268 
269   /* Get all pending and enabled interrupts. */
270   pending  = DMA->IF;
271   pending &= DMA->IEN;
272 
273   /* Assert on bus error. */
274   EFM_ASSERT(!(pending & DMA_IF_ERR));
275 
276   /* Process all pending channel interrupts. First process channels */
277   /* defined with high priority, then those with default priority. */
278   prio        = DMA->CHPRIS;
279   pendingPrio = pending & prio;
280   for (i = 0; i < 2; i++) {
281     channel = 0;
282     /* Process pending interrupts within high/default priority group */
283     /* honoring the priority within the group. */
284     while (pendingPrio) {
285       if (pendingPrio & 1) {
286         DMA_DESCRIPTOR_TypeDef *descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE);
287         uint32_t chmask = 1 << channel;
288 
289         /* Clear a pending interrupt prior to invoking the callback, in case it */
290         /* sets up another DMA cycle. */
291         DMA->IFC = chmask;
292 
293         /* Normally, no point in enabling interrupt without the callback, but */
294         /* check if the callback is defined anyway. Callback information is always */
295         /* located in the primary descriptor. */
296         cb = (DMA_CB_TypeDef *)(descr[channel].USER);
297         if (cb) {
298           /* Toggle next-descriptor indicator always prior to invoking */
299           /* callback (in case callback reconfigures something). */
300           primaryCpy   = cb->primary;
301           cb->primary ^= 1;
302           if (cb->cbFunc) {
303             cb->cbFunc(channel, (bool)primaryCpy, cb->userPtr);
304           }
305         }
306       }
307 
308       pendingPrio >>= 1;
309       channel++;
310     }
311 
312     /* On second iteration, process default priority channels. */
313     pendingPrio = pending & ~prio;
314   }
315 }
316 
317 #endif /* EXCLUDE_DEFAULT_DMA_IRQ_HANDLER */
318 
319 /*******************************************************************************
320  **************************   GLOBAL FUNCTIONS   *******************************
321  ******************************************************************************/
322 
323 /***************************************************************************//**
324  * @brief
325  *   Activate the DMA auto-request cycle (used for memory-memory transfers).
326  *
327  * @details
328  *   Prior to activating the DMA cycle, the channel and descriptor to be used
329  *   must have been properly configured.
330  *
331  * @note
332  *   If using this function on a channel already activated and in use by the
333  *   DMA controller, the behavior is undefined.
334  *
335  * @param[in] channel
336  *   The DMA channel to activate the DMA cycle for.
337  *
338  * @param[in] primary
339  *   @li true - activate using the primary descriptor
340  *   @li false - activate using an alternate descriptor
341  *
342  * @param[in] dst
343  *   An ddress to a start location to transfer data to. If NULL, leave setting in
344  *   descriptor as is from a previous activation.
345  *
346  * @param[in] src
347  *   An address to a start location to transfer data from. If NULL, leave setting in
348  *   descriptor as is from a previous activation.
349  *
350  * @param[in] nMinus1
351  *   A number of DMA transfer elements (minus 1) to transfer (<= 1023). The
352  *   size of the DMA transfer element (1, 2 or 4 bytes) is configured with
353  *   DMA_CfgDescr().
354  ******************************************************************************/
DMA_ActivateAuto(unsigned int channel,bool primary,void * dst,const void * src,unsigned int nMinus1)355 void DMA_ActivateAuto(unsigned int channel,
356                       bool primary,
357                       void *dst,
358                       const void *src,
359                       unsigned int nMinus1)
360 {
361   uint32_t chBit;
362 
363   EFM_ASSERT(channel < DMA_CHAN_COUNT);
364   EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
365 
366   DMA_Prepare(channel,
367               dmaCycleCtrlAuto,
368               primary,
369               false,
370               dst,
371               src,
372               nMinus1);
373 
374   chBit        = 1 << channel;
375   DMA->CHENS   = chBit; /* Enable the channel. */
376   DMA->CHSWREQ = chBit; /* Activate with the software request. */
377 }
378 
379 /***************************************************************************//**
380  * @brief
381  *   Activate the DMA basic cycle (used for memory-peripheral transfers).
382  *
383  * @details
384  *   Prior to activating the DMA cycle, the channel and descriptor to be used
385  *   must have been properly configured.
386  *
387  * @note
388  *   If using this function on a channel already activated and in use by the
389  *   DMA controller, the behavior is undefined.
390  *
391  * @param[in] channel
392  *   The DMA channel to activate the DMA cycle for.
393  *
394  * @param[in] primary
395  *   @li true - activate using the primary descriptor
396  *   @li false - activate using an alternate descriptor
397  *
398  * @param[in] useBurst
399  *   The burst feature is only used on peripherals supporting DMA bursts.
400  *   Bursts must not be used if the total length (as given by nMinus1) is
401  *   less than the arbitration rate configured for the descriptor.
402  *   See the reference manual for more details on burst usage.
403  *
404  * @param[in] dst
405  *   An address to a start location to transfer data to. If NULL, leave setting in
406  *   descriptor as is from a previous activation.
407  *
408  * @param[in] src
409  *   An address to a start location to transfer data from. If NULL, leave setting in
410  *   descriptor as is from a previous activation.
411  *
412  * @param[in] nMinus1
413  *   A number of DMA transfer elements (minus 1) to transfer (<= 1023). The
414  *   size of the DMA transfer element (1, 2 or 4 bytes) is configured with
415  *   DMA_CfgDescr().
416  ******************************************************************************/
DMA_ActivateBasic(unsigned int channel,bool primary,bool useBurst,void * dst,const void * src,unsigned int nMinus1)417 void DMA_ActivateBasic(unsigned int channel,
418                        bool primary,
419                        bool useBurst,
420                        void *dst,
421                        const void *src,
422                        unsigned int nMinus1)
423 {
424   EFM_ASSERT(channel < DMA_CHAN_COUNT);
425   EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
426 
427   DMA_Prepare(channel,
428               dmaCycleCtrlBasic,
429               primary,
430               useBurst,
431               dst,
432               src,
433               nMinus1);
434 
435   /* Enable channel, request signal is provided by the peripheral device. */
436   DMA->CHENS = 1 << channel;
437 }
438 
439 /***************************************************************************//**
440  * @brief
441  *   Activate a DMA ping-pong cycle (used for memory-peripheral transfers).
442  *
443  * @details
444  *   Prior to activating the DMA cycle, the channel and both descriptors must
445  *   have been properly configured. The primary descriptor is always the first
446  *   descriptor to be used by the DMA controller.
447  *
448  * @note
449  *   If using this function on a channel already activated and in use by the
450  *   DMA controller, the behavior is undefined.
451  *
452  * @param[in] channel
453  *   The DMA channel to activate DMA cycle for.
454  *
455  * @param[in] useBurst
456  *   The burst feature is only used on peripherals supporting DMA bursts.
457  *   Bursts must not be used if the total length (as given by nMinus1) is
458  *   less than the arbitration rate configured for the descriptors.
459  *   See the reference manual for more details on burst usage. Notice
460  *   that this setting is used for both the primary and alternate descriptors.
461  *
462  * @param[in] primDst
463  *   An address to a start location to transfer data to, for the primary descriptor.
464  *   If NULL, leave setting in descriptor as is from a previous activation.
465  *
466  * @param[in] primSrc
467  *   An address to a start location to transfer data from, for the primary descriptor.
468  *   If NULL, leave setting in the descriptor as is from a previous activation.
469  *
470  * @param[in] primNMinus1
471  *   A number of DMA transfer elements (minus 1) to transfer (<= 1023), for
472  *   primary descriptor. The size of the DMA transfer element (1, 2 or 4 bytes)
473  *   is configured with DMA_CfgDescr().
474  *
475  * @param[in] altDst
476  *   An address to a start location to transfer data to, for an alternate descriptor.
477  *   If NULL, leave setting in descriptor as is from a previous activation.
478  *
479  * @param[in] altSrc
480  *   An address to a start location to transfer data from, for an alternate descriptor.
481  *   If NULL, leave setting in descriptor as is from a previous activation.
482  *
483  * @param[in] altNMinus1
484  *   A number of DMA transfer elements (minus 1) to transfer (<= 1023), for
485  *   an alternate descriptor. The size of the DMA transfer element (1, 2 or 4 bytes)
486  *   is configured with DMA_CfgDescr().
487  ******************************************************************************/
DMA_ActivatePingPong(unsigned int channel,bool useBurst,void * primDst,const void * primSrc,unsigned int primNMinus1,void * altDst,const void * altSrc,unsigned int altNMinus1)488 void DMA_ActivatePingPong(unsigned int channel,
489                           bool useBurst,
490                           void *primDst,
491                           const void *primSrc,
492                           unsigned int primNMinus1,
493                           void *altDst,
494                           const void *altSrc,
495                           unsigned int altNMinus1)
496 {
497   EFM_ASSERT(channel < DMA_CHAN_COUNT);
498   EFM_ASSERT(primNMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
499   EFM_ASSERT(altNMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
500 
501   /* Prepare alternate descriptor first */
502   DMA_Prepare(channel,
503               dmaCycleCtrlPingPong,
504               false,
505               useBurst,
506               altDst,
507               altSrc,
508               altNMinus1);
509 
510   /* Prepare the primary descriptor last to start a cycle using it. */
511   DMA_Prepare(channel,
512               dmaCycleCtrlPingPong,
513               true,
514               useBurst,
515               primDst,
516               primSrc,
517               primNMinus1);
518 
519   /* Enable the channel, the request signal is provided by the peripheral device. */
520   DMA->CHENS = 1 << channel;
521 }
522 
523 /***************************************************************************//**
524  * @brief
525  *   Activate the DMA scatter-gather cycle (used for either memory-peripheral
526  *   or memory-memory transfers).
527  *
528  * @details
529  *   Prior to activating the DMA cycle, the array with alternate descriptors
530  *   must have been properly configured. This function can be reused without
531  *   reconfiguring the alternate descriptors, as long as @p count is the same.
532  *
533  * @note
534  *   If using this function on a channel already activated and in use by the
535  *   DMA controller, the behavior is undefined.
536  *
537  * @param[in] channel
538  *   The DMA channel to activate DMA cycle for.
539  *
540  * @param[in] useBurst
541  *   The burst feature is only used on peripherals supporting DMA bursts
542  *   (this parameter is ignored for memory scatter-gather cycles).
543  *   This parameter determines if bursts should be enabled during DMA transfers
544  *   using the alternate descriptors. Bursts must not be used if the total
545  *   length (as given by nMinus1 for the alternate descriptor) is
546  *   less than the arbitration rate configured for the descriptor.
547  *   See the reference manual for more details on burst usage.
548  *
549  * @param[in,out] altDescr
550  *   A pointer to a start of an array with prepared alternate descriptors. The last
551  *   descriptor will have its cycle control type reprogrammed to a basic type.
552  *
553  * @param[in] count
554  *   A number of alternate descriptors in @p altDescr array. The maximum number of
555  *   alternate descriptors is 256.
556  ******************************************************************************/
DMA_ActivateScatterGather(unsigned int channel,bool useBurst,DMA_DESCRIPTOR_TypeDef * altDescr,unsigned int count)557 void DMA_ActivateScatterGather(unsigned int channel,
558                                bool useBurst,
559                                DMA_DESCRIPTOR_TypeDef *altDescr,
560                                unsigned int count)
561 {
562   DMA_DESCRIPTOR_TypeDef *descr;
563   DMA_CB_TypeDef         *cb;
564   uint32_t               cycleCtrl;
565   uint32_t               chBit;
566 
567   EFM_ASSERT(channel < DMA_CHAN_COUNT);
568   EFM_ASSERT(altDescr);
569   EFM_ASSERT(count && (count <= 256));
570 
571   /* Configure the primary descriptor properly to */
572   /* transfer one complete alternate descriptor from the alternate */
573   /* descriptor table into the actual alternate descriptor. */
574   descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE) + channel;
575 
576   /* Set the source end address to point to the alternate descriptor array. */
577   descr->SRCEND = (uint32_t *)altDescr + (count * 4) - 1;
578 
579   /* The destination end address in the primary descriptor MUST point */
580   /* to the corresponding alternate descriptor in scatter-gather mode. */
581   descr->DSTEND = (uint32_t *)((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)
582                                + channel + 1) - 1;
583 
584   /* The user field of the descriptor is used for the callback configuration */
585   /* and is already configured when the channel is configured. Do not modify it. */
586 
587   /* Determine from alternate configuration whether this is a memory or a */
588   /* peripheral scatter-gather by looking at the first alternate descriptor. */
589   cycleCtrl  = altDescr->CTRL & _DMA_CTRL_CYCLE_CTRL_MASK;
590   cycleCtrl &= ~(1 << _DMA_CTRL_CYCLE_CTRL_SHIFT);
591 
592   EFM_ASSERT((cycleCtrl == dmaCycleCtrlMemScatterGather)
593              || (cycleCtrl == dmaCycleCtrlPerScatterGather));
594 
595   /* Set the last alternate descriptor to basic or auto-request a cycle type in */
596   /* order to have dma_done signal asserted when complete. Otherwise, an interrupt */
597   /* will not be triggered when done. */
598   altDescr[count - 1].CTRL &= ~_DMA_CTRL_CYCLE_CTRL_MASK;
599   if (cycleCtrl == dmaCycleCtrlMemScatterGather) {
600     altDescr[count - 1].CTRL |= (uint32_t)dmaCycleCtrlAuto
601                                 << _DMA_CTRL_CYCLE_CTRL_SHIFT;
602   } else {
603     altDescr[count - 1].CTRL |= (uint32_t)dmaCycleCtrlBasic
604                                 << _DMA_CTRL_CYCLE_CTRL_SHIFT;
605   }
606 
607   /* If the callback is defined, update the information on whether the callback is issued for */
608   /* primary or alternate descriptors. Not really useful for scatter-gather */
609   /* but there for consistency. Always set to alternate, since that is the last */
610   /* descriptor used. */
611   cb = (DMA_CB_TypeDef *)(descr->USER);
612   if (cb) {
613     cb->primary = false;
614   }
615 
616   /* Configure the primary descriptor control word. */
617   descr->CTRL = ((uint32_t)dmaDataInc4 << _DMA_CTRL_DST_INC_SHIFT)
618                 | ((uint32_t)dmaDataSize4 << _DMA_CTRL_DST_SIZE_SHIFT)
619                 | ((uint32_t)dmaDataInc4 << _DMA_CTRL_SRC_INC_SHIFT)
620                 | ((uint32_t)dmaDataSize4 << _DMA_CTRL_SRC_SIZE_SHIFT)
621                 /* Use the same protection scheme as for alternate descriptors. */
622                 | (altDescr->CTRL & _DMA_CTRL_SRC_PROT_CTRL_MASK)
623                 | ((uint32_t)dmaArbitrate4 << _DMA_CTRL_R_POWER_SHIFT)
624                 | (((count * 4) - 1) << _DMA_CTRL_N_MINUS_1_SHIFT)
625                 | (((uint32_t)useBurst & 1) << _DMA_CTRL_NEXT_USEBURST_SHIFT)
626                 | cycleCtrl;
627 
628   chBit = 1 << channel;
629 
630   /* Start with the primary descriptor. */
631   DMA->CHALTC = chBit;
632 
633   /* Enable the channel. */
634   DMA->CHENS = chBit;
635 
636   /* Send a request if memory scatter-gather. Otherwise, the request signal is */
637   /* provided by the peripheral. */
638   if (cycleCtrl == dmaCycleCtrlMemScatterGather) {
639     DMA->CHSWREQ = chBit;
640   }
641 }
642 
643 /***************************************************************************//**
644  * @brief
645  *   Configure a DMA channel.
646  *
647  * @details
648  *   Configure miscellaneous issues for a DMA channel. This function is typically
649  *   used once to set up a channel for a certain type of use.
650  *
651  * @note
652  *   If using this function on a channel already in use by the DMA controller,
653  *   the behavior is undefined.
654  *
655  * @param[in] channel
656  *   The DMA channel to configure.
657  *
658  * @param[in] cfg
659  *   The configuration to use.
660  ******************************************************************************/
DMA_CfgChannel(unsigned int channel,DMA_CfgChannel_TypeDef * cfg)661 void DMA_CfgChannel(unsigned int channel, DMA_CfgChannel_TypeDef *cfg)
662 {
663   DMA_DESCRIPTOR_TypeDef *descr;
664 
665   EFM_ASSERT(channel < DMA_CHAN_COUNT);
666   EFM_ASSERT(cfg);
667 
668   /* Always keep callback configuration reference in the primary descriptor. */
669   descr               = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE);
670   descr[channel].USER = (uint32_t)(cfg->cb);
671 
672   /* Set to a specified priority for a channel. */
673   if (cfg->highPri) {
674     DMA->CHPRIS = 1 << channel;
675   } else {
676     DMA->CHPRIC = 1 << channel;
677   }
678 
679   /* Set the DMA signal source select. */
680   DMA->CH[channel].CTRL = cfg->select;
681 
682   /* Enable/disable an interrupt as specified. */
683   if (cfg->enableInt) {
684     DMA->IFC = (1 << channel);
685     BUS_RegBitWrite(&(DMA->IEN), channel, 1);
686   } else {
687     BUS_RegBitWrite(&(DMA->IEN), channel, 0);
688   }
689 }
690 
691 /***************************************************************************//**
692  * @brief
693  *   Configure the DMA descriptor for auto-request, basic, or ping-pong DMA cycles.
694  *
695  * @details
696  *   This function is used to configure a descriptor for the following
697  *   DMA cycle types:
698  *
699  *   @li auto-request - used for a memory/memory transfer
700  *   @li basic - used for a peripheral/memory transfer
701  *   @li ping-pong - used for a ping-pong-based peripheral/memory transfer
702  *     style providing time to refresh one descriptor while the other is
703  *     in use.
704  *
705  *   The DMA cycle is not activated. See DMA_ActivateAuto(),
706  *   DMA_ActivateBasic(), or DMA_ActivatePingPong() to activate the DMA cycle.
707  *   In many cases, the configuration only has to be done once, and all
708  *   subsequent cycles may be activated with the activate function.
709  *
710  *   For ping-pong DMA cycles, this function must be used both on the primary
711  *   and the alternate descriptor prior to activating the DMA cycle.
712  *
713  *   Notice that the DMA channel must also be configured. See DMA_CfgChannel().
714  *
715  * @note
716  *   If using this function on a descriptor already activated and in use by
717  *   the DMA controller, the behavior is undefined.
718  *
719  * @param[in] channel
720  *   The DMA channel to configure for.
721  *
722  * @param[in] primary
723  *   @li true - configure the primary descriptor
724  *   @li false - configure an alternate descriptor
725  *
726  * @param[in] cfg
727  *   The configuration to use.
728  ******************************************************************************/
DMA_CfgDescr(unsigned int channel,bool primary,DMA_CfgDescr_TypeDef * cfg)729 void DMA_CfgDescr(unsigned int channel,
730                   bool primary,
731                   DMA_CfgDescr_TypeDef *cfg)
732 {
733   DMA_DESCRIPTOR_TypeDef *descr;
734 
735   EFM_ASSERT(channel < DMA_CHAN_COUNT);
736   EFM_ASSERT(cfg);
737 
738   /* Find a descriptor to configure. */
739   if (primary) {
740     descr = (DMA_DESCRIPTOR_TypeDef *)DMA->CTRLBASE;
741   } else {
742     descr = (DMA_DESCRIPTOR_TypeDef *)DMA->ALTCTRLBASE;
743   }
744   descr += channel;
745 
746   /* Prepare the descriptor. */
747   /* The source/destination end addresses set when started. */
748   descr->CTRL = (cfg->dstInc << _DMA_CTRL_DST_INC_SHIFT)
749                 | (cfg->size << _DMA_CTRL_DST_SIZE_SHIFT)
750                 | (cfg->srcInc << _DMA_CTRL_SRC_INC_SHIFT)
751                 | (cfg->size << _DMA_CTRL_SRC_SIZE_SHIFT)
752                 | ((uint32_t)(cfg->hprot) << _DMA_CTRL_SRC_PROT_CTRL_SHIFT)
753                 | (cfg->arbRate << _DMA_CTRL_R_POWER_SHIFT)
754                 | (0 << _DMA_CTRL_N_MINUS_1_SHIFT)     /* Set when activated. */
755                 | (0 << _DMA_CTRL_NEXT_USEBURST_SHIFT) /* Set when activated. */
756                 | DMA_CTRL_CYCLE_CTRL_INVALID;         /* Set when activated. */
757 }
758 
759 #if defined(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK)
760 /***************************************************************************//**
761  * @brief Configure the DMA channel for Loop mode or 2D transfer.
762  *
763  * @details
764  *   For 2D transfer, set cfg->enable to "false" and only configure nMinus1
765  *   to the same width as the channel descriptor.
766  *
767  * @param[in] channel
768  *   The DMA channel to configure for.
769  *
770  * @param[in] cfg
771  *   The configuration to use.
772  ******************************************************************************/
DMA_CfgLoop(unsigned int channel,DMA_CfgLoop_TypeDef * cfg)773 void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg)
774 {
775   EFM_ASSERT(channel <= 1);
776   EFM_ASSERT(cfg->nMinus1 <= 1023);
777 
778   /* Configure the LOOP setting. */
779   switch ( channel ) {
780     case 0:
781       DMA->LOOP0 = (cfg->enable    << _DMA_LOOP0_EN_SHIFT)
782                    | (cfg->nMinus1 << _DMA_LOOP0_WIDTH_SHIFT);
783       break;
784     case 1:
785       DMA->LOOP1 = (cfg->enable    << _DMA_LOOP1_EN_SHIFT)
786                    | (cfg->nMinus1 << _DMA_LOOP1_WIDTH_SHIFT);
787       break;
788   }
789 }
790 #endif
791 
792 #if defined(_DMA_RECT0_MASK)
793 /***************************************************************************//**
794  * @brief Configure the DMA channel 2D transfer properties.
795  *
796  * @param[in] channel
797  *   The DMA channel to configure for.
798  *
799  * @param[in] cfg
800  *   The configuration to use.
801  ******************************************************************************/
DMA_CfgRect(unsigned int channel,DMA_CfgRect_TypeDef * cfg)802 void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg)
803 {
804   (void)channel;                            /* Unused parameter */
805 
806   EFM_ASSERT(channel == 0);
807   EFM_ASSERT(cfg->dstStride <= 2047);
808   EFM_ASSERT(cfg->srcStride <= 2047);
809   EFM_ASSERT(cfg->height <= 1023);
810 
811   /* Configure the rectangular/2D copy. */
812   DMA->RECT0 = (cfg->dstStride   << _DMA_RECT0_DSTSTRIDE_SHIFT)
813                | (cfg->srcStride << _DMA_RECT0_SRCSTRIDE_SHIFT)
814                | (cfg->height    << _DMA_RECT0_HEIGHT_SHIFT);
815 }
816 #endif
817 
818 /***************************************************************************//**
819  * @brief
820  *   Configure an alternate DMA descriptor for use with scatter-gather DMA
821  *   cycles.
822  *
823  * @details
824  *   In scatter-gather mode, the alternate descriptors are located in one
825  *   contiguous memory area. Each of the alternate descriptors must be fully
826  *   configured prior to starting the scatter-gather DMA cycle.
827  *
828  *   The DMA cycle is not activated by this function. See
829  *   DMA_ActivateScatterGather() to activate the DMA cycle. In some cases, the
830  *   alternate configuration only has to be done once and all subsequent
831  *   transfers may be activated with the activate function.
832  *
833  *   Notice that the DMA channel must also be configured, see DMA_CfgChannel().
834  *
835  * @param[in] descr
836  *   Points to the start of a memory area holding the alternate descriptors.
837  *
838  * @param[in] indx
839  *   An alternate descriptor index number to configure (numbered from 0).
840  *
841  * @param[in] cfg
842  *   The configuration to use.
843  ******************************************************************************/
DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef * descr,unsigned int indx,DMA_CfgDescrSGAlt_TypeDef * cfg)844 void DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef *descr,
845                                unsigned int indx,
846                                DMA_CfgDescrSGAlt_TypeDef *cfg)
847 {
848   uint32_t cycleCtrl;
849 
850   EFM_ASSERT(descr);
851   EFM_ASSERT(cfg);
852 
853   /* Point to a selected entry in the alternate descriptor table. */
854   descr += indx;
855 
856   if (cfg->srcInc == dmaDataIncNone) {
857     descr->SRCEND = cfg->src;
858   } else {
859     descr->SRCEND = (void *)((uint32_t)(cfg->src)
860                              + ((uint32_t)(cfg->nMinus1) << cfg->srcInc));
861   }
862 
863   if (cfg->dstInc == dmaDataIncNone) {
864     descr->DSTEND = cfg->dst;
865   } else {
866     descr->DSTEND = (void *)((uint32_t)(cfg->dst)
867                              + ((uint32_t)(cfg->nMinus1) << cfg->dstInc));
868   }
869 
870   /* User-definable part not used. */
871   descr->USER = 0;
872 
873   if (cfg->peripheral) {
874     cycleCtrl = (uint32_t)dmaCycleCtrlPerScatterGather + 1;
875   } else {
876     cycleCtrl = (uint32_t)dmaCycleCtrlMemScatterGather + 1;
877   }
878 
879   descr->CTRL = (cfg->dstInc << _DMA_CTRL_DST_INC_SHIFT)
880                 | (cfg->size << _DMA_CTRL_DST_SIZE_SHIFT)
881                 | (cfg->srcInc << _DMA_CTRL_SRC_INC_SHIFT)
882                 | (cfg->size << _DMA_CTRL_SRC_SIZE_SHIFT)
883                 | ((uint32_t)(cfg->hprot) << _DMA_CTRL_SRC_PROT_CTRL_SHIFT)
884                 | (cfg->arbRate << _DMA_CTRL_R_POWER_SHIFT)
885                 | ((uint32_t)(cfg->nMinus1) << _DMA_CTRL_N_MINUS_1_SHIFT)
886                 /* Never set next useburst bit since the descriptor used after the */
887                 /* alternate descriptor is the primary descriptor which operates on */
888                 /* memory. If the alternate descriptors need to have useBurst set, this */
889                 /* is done when setting up the primary descriptor, i.e., when activating. */
890                 | (0 << _DMA_CTRL_NEXT_USEBURST_SHIFT)
891                 | (cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT);
892 }
893 
894 /***************************************************************************//**
895  * @brief
896  *   Enable or disable a DMA channel.
897  *
898  * @details
899  *   Use this function to explicitly enable or disable a DMA channel. A DMA
900  *   channel is automatically disabled when the DMA controller has finished a
901  *   transaction.
902  *
903  * @param[in] channel
904  *   The DMA channel to enable or disable.
905  *
906  * @param[in] enable
907  *   If 'true', the channel will be enabled. If 'false', the channel will be
908  *   disabled.
909  ******************************************************************************/
DMA_ChannelEnable(unsigned int channel,bool enable)910 void DMA_ChannelEnable(unsigned int channel, bool enable)
911 {
912   EFM_ASSERT(channel < DMA_CHAN_COUNT);
913 
914   if (enable) {
915     DMA->CHENS = 1 << channel;
916   } else {
917     DMA->CHENC = 1 << channel;
918   }
919 }
920 
921 /***************************************************************************//**
922  * @brief
923  *   Check if the DMA channel is enabled.
924  *
925  * @details
926  *   The DMA channel is disabled when the DMA controller has finished a DMA
927  *   cycle.
928  *
929  * @param[in] channel
930  *   The DMA channel to check.
931  *
932  * @return
933  *   True if the channel is enabled, false if not.
934  ******************************************************************************/
DMA_ChannelEnabled(unsigned int channel)935 bool DMA_ChannelEnabled(unsigned int channel)
936 {
937   EFM_ASSERT(channel < DMA_CHAN_COUNT);
938 
939   return (bool)((DMA->CHENS >> channel) & 1);
940 }
941 
942 /***************************************************************************//**
943  * @brief
944  *   Enable or disable a DMA channel request.
945  *
946  * @details
947  *   Use this function to enable or disable a DMA channel request. This will
948  *   prevent the DMA from proceeding after its current transaction if disabled.
949  *
950  * @param[in] channel
951  *   The DMA channel to enable or disable the request on.
952  *
953  * @param[in] enable
954  *   If 'true', the request will be enabled. If 'false', the request will be disabled.
955  ******************************************************************************/
DMA_ChannelRequestEnable(unsigned int channel,bool enable)956 void DMA_ChannelRequestEnable(unsigned int channel, bool enable)
957 {
958   EFM_ASSERT(channel < DMA_CHAN_COUNT);
959 
960   if (enable) {
961     BUS_RegBitWrite(&DMA->CHREQMASKC, channel, 1);
962   } else {
963     BUS_RegBitWrite(&DMA->CHREQMASKS, channel, 1);
964   }
965 }
966 
967 /***************************************************************************//**
968  * @brief
969  *   Initialize the DMA controller.
970  *
971  * @details
972  *   This function resets and prepares the DMA controller for use. Although
973  *   it may be used several times, it is normally only used during system
974  *   initialization. If reused during a normal operation, any ongoing DMA
975  *   transfers will be aborted. When complete, the DMA controller is in
976  *   an enabled state.
977  *
978  * @note
979  *   Must be invoked before using the DMA controller.
980  *
981  * @param[in] init
982  *   A pointer to a structure containing the DMA initialization information.
983  ******************************************************************************/
DMA_Init(DMA_Init_TypeDef * init)984 void DMA_Init(DMA_Init_TypeDef *init)
985 {
986   EFM_ASSERT(init);
987 
988   /* Make sure that the control block is properly aligned. */
989 #if (DMA_CHAN_COUNT <= 4)
990   EFM_ASSERT(!((uint32_t)(init->controlBlock) & (128 - 1)));
991 #elif (DMA_CHAN_COUNT <= 8) || (DMA_CHAN_COUNT <= 12)
992   EFM_ASSERT(!((uint32_t)(init->controlBlock) & (256 - 1)));
993 #else
994 #error "Unsupported DMA channel count (em_dma.c)."
995 #endif
996 
997   /* Make sure that the DMA clock is enabled prior to accessing the DMA module. */
998   CMU_ClockEnable(cmuClock_DMA, true);
999 
1000   /* Make sure that the DMA controller is set to a known reset state. */
1001   DMA_Reset();
1002 
1003   /* Clear/enable DMA interrupts. */
1004   NVIC_ClearPendingIRQ(DMA_IRQn);
1005   NVIC_EnableIRQ(DMA_IRQn);
1006 
1007   /* Enable the bus error interrupt. */
1008   DMA->IEN = DMA_IEN_ERR;
1009 
1010   /* Set the pointer to a control block. Notice that the pointer must have been */
1011   /* properly aligned according to requirements defined in the reference */
1012   /* manual. */
1013   DMA->CTRLBASE = (uint32_t)(init->controlBlock);
1014 
1015   /* Configure and enable the DMA controller. */
1016   DMA->CONFIG = ((uint32_t)(init->hprot) << _DMA_CONFIG_CHPROT_SHIFT)
1017                 | DMA_CONFIG_EN;
1018 }
1019 
1020 /***************************************************************************//**
1021  * @brief
1022  *   Refresh a descriptor used in a DMA ping-pong cycle.
1023  *
1024  * @details
1025  *   During a ping-pong DMA cycle, the DMA controller automatically alternates
1026  *   between the primary and alternate descriptors, when completing use of a
1027  *   descriptor. While the other descriptor is in use by the DMA controller,
1028  *   the software should refresh the completed descriptor. This is typically done from
1029  *   the callback defined for the ping-pong cycle.
1030  *
1031  * @param[in] channel
1032  *   The DMA channel to refresh the ping-pong descriptor for.
1033  *
1034  * @param[in] primary
1035  *   @li true - refresh the primary descriptor
1036  *   @li false - refresh an alternate descriptor
1037  *
1038  * @param[in] useBurst
1039  *   The burst feature is only used on peripherals supporting DMA bursts.
1040  *   Bursts must not be used if the total length (as given by nMinus1) is
1041  *   less than the arbitration rate configured for the descriptor.
1042  *   See the reference manual for more details on burst usage.
1043  *
1044  * @param[in] dst
1045  *   An address to a start location to transfer data to. If NULL, leave setting in
1046  *   descriptor as is.
1047  *
1048  * @param[in] src
1049  *   An address to a start location to transfer data from. If NULL, leave setting in
1050  *   descriptor as is.
1051  *
1052  * @param[in] nMinus1
1053  *   A number of DMA transfer elements (minus 1) to transfer (<= 1023). The
1054  *   size of the DMA transfer element (1, 2 or 4 bytes) is configured with
1055  *   DMA_CfgDescr().
1056  *
1057  * @param[in] stop
1058  *   Indicate that the DMA ping-pong cycle stops @b when done using
1059  *   this descriptor.
1060  ******************************************************************************/
DMA_RefreshPingPong(unsigned int channel,bool primary,bool useBurst,void * dst,const void * src,unsigned int nMinus1,bool stop)1061 void DMA_RefreshPingPong(unsigned int channel,
1062                          bool primary,
1063                          bool useBurst,
1064                          void *dst,
1065                          const void *src,
1066                          unsigned int nMinus1,
1067                          bool stop)
1068 {
1069   DMA_CycleCtrl_TypeDef  cycleCtrl;
1070   DMA_DESCRIPTOR_TypeDef *descr;
1071   uint32_t               inc;
1072   uint32_t               chBit;
1073   uint32_t               tmp;
1074 
1075   EFM_ASSERT(channel < DMA_CHAN_COUNT);
1076   EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
1077 
1078   /* The ping-pong DMA cycle may be stopped by issuing a basic cycle type. */
1079   if (stop) {
1080     cycleCtrl = dmaCycleCtrlBasic;
1081   } else {
1082     cycleCtrl = dmaCycleCtrlPingPong;
1083   }
1084 
1085   /* Find a descriptor to configure. */
1086   if (primary) {
1087     descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE)) + channel;
1088   } else {
1089     descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)) + channel;
1090   }
1091 
1092   if (src) {
1093     inc = (descr->CTRL & _DMA_CTRL_SRC_INC_MASK) >> _DMA_CTRL_SRC_INC_SHIFT;
1094     if (inc == _DMA_CTRL_SRC_INC_NONE) {
1095       descr->SRCEND = (volatile void*)src;
1096     } else {
1097       descr->SRCEND = (void *)((uint32_t)src + (nMinus1 << inc));
1098     }
1099   }
1100 
1101   if (dst) {
1102     inc = (descr->CTRL & _DMA_CTRL_DST_INC_MASK) >> _DMA_CTRL_DST_INC_SHIFT;
1103     if (inc == _DMA_CTRL_DST_INC_NONE) {
1104       descr->DSTEND = dst;
1105     } else {
1106       descr->DSTEND = (void *)((uint32_t)dst + (nMinus1 << inc));
1107     }
1108   }
1109 
1110   chBit = 1 << channel;
1111   if (useBurst) {
1112     DMA->CHUSEBURSTS = chBit;
1113   } else {
1114     DMA->CHUSEBURSTC = chBit;
1115   }
1116 
1117   /* Set cycle control. */
1118   tmp  = descr->CTRL & ~(_DMA_CTRL_CYCLE_CTRL_MASK | _DMA_CTRL_N_MINUS_1_MASK);
1119   tmp |= nMinus1 << _DMA_CTRL_N_MINUS_1_SHIFT;
1120   tmp |= cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT;
1121   descr->CTRL = tmp;
1122 }
1123 
1124 /***************************************************************************//**
1125  * @brief
1126  *   Reset the DMA controller.
1127  *
1128  * @details
1129  *   This functions will disable the DMA controller and set it to a reset
1130  *   state.
1131  *
1132  * @note
1133  *   Note that any ongoing transfers will be aborted.
1134  ******************************************************************************/
DMA_Reset(void)1135 void DMA_Reset(void)
1136 {
1137   int i;
1138 
1139   /* Disable DMA interrupts */
1140   NVIC_DisableIRQ(DMA_IRQn);
1141 
1142   /* Put the DMA controller into a known state, first disabling it. */
1143   DMA->CONFIG      = _DMA_CONFIG_RESETVALUE;
1144   DMA->CHUSEBURSTC = _DMA_CHUSEBURSTC_MASK;
1145   DMA->CHREQMASKC  = _DMA_CHREQMASKC_MASK;
1146   DMA->CHENC       = _DMA_CHENC_MASK;
1147   DMA->CHALTC      = _DMA_CHALTC_MASK;
1148   DMA->CHPRIC      = _DMA_CHPRIC_MASK;
1149   DMA->ERRORC      = DMA_ERRORC_ERRORC;
1150   DMA->IEN         = _DMA_IEN_RESETVALUE;
1151   DMA->IFC         = _DMA_IFC_MASK;
1152 
1153   /* Clear channel control flags. */
1154   for (i = 0; i < DMA_CHAN_COUNT; i++) {
1155     DMA->CH[i].CTRL = _DMA_CH_CTRL_RESETVALUE;
1156   }
1157 }
1158 
1159 /** @} (end addtogroup dma) */
1160 #endif /* defined( DMA_PRESENT ) */
1161