1 /**
2  * @file    dma.h
3  * @brief   Direct Memory Access (DMA) driver function prototypes and data types.
4  */
5 
6 /******************************************************************************
7  *
8  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
9  * Analog Devices, Inc.),
10  * Copyright (C) 2023-2024 Analog Devices, Inc.
11  *
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  *
24  ******************************************************************************/
25 
26 #ifndef LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32660_DMA_H_
27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32660_DMA_H_
28 
29 /* **** Includes **** */
30 #include <stdbool.h>
31 #include "mxc_device.h"
32 #include "mxc_errors.h"
33 #include "dma_regs.h"
34 
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
38 
39 /**
40  * @defgroup dma Direct Memory Access (DMA)
41  * @ingroup periphlibs
42  * @{
43  */
44 
45 /* **** Definitions **** */
46 
47 /**
48  * @brief   Enumeration for the DMA Channel's priority level.
49  *
50  */
51 typedef enum {
52     MXC_DMA_PRIO_HIGH = MXC_V_DMA_CFG_PRI_HIGH, ///< High Priority */
53     MXC_DMA_PRIO_MEDHIGH = MXC_V_DMA_CFG_PRI_MEDHIGH, ///< Medium High Priority */
54     MXC_DMA_PRIO_MEDLOW = MXC_V_DMA_CFG_PRI_MEDLOW, ///< Medium Low Priority */
55     MXC_DMA_PRIO_LOW = MXC_V_DMA_CFG_PRI_LOW, ///< Low Priority */
56 } mxc_dma_priority_t;
57 
58 /** @brief DMA request select */
59 typedef enum {
60     MXC_DMA_REQUEST_MEMTOMEM =
61         MXC_S_DMA_CFG_REQSEL_MEMTOMEM, ///< Memory to Memory DMA Request Selection
62     MXC_DMA_REQUEST_SPI0RX = MXC_S_DMA_CFG_REQSEL_SPI0RX, ///< SPI0 Receive DMA Request Selection
63     MXC_DMA_REQUEST_SPIMSSRX =
64         MXC_S_DMA_CFG_REQSEL_SPI1RX, ///< SPIMSS Receive DMA Request Selection
65     MXC_DMA_REQUEST_UART0RX = MXC_S_DMA_CFG_REQSEL_UART0RX, ///< UART0 Receive DMA Request Selection
66     MXC_DMA_REQUEST_UART1RX = MXC_S_DMA_CFG_REQSEL_UART1RX, ///< UART1 Receive DMA Request Selection
67     MXC_DMA_REQUEST_I2C0RX = MXC_S_DMA_CFG_REQSEL_I2C0RX, ///< I2C0 Receive DMA Request Selection
68     MXC_DMA_REQUEST_I2C1RX = MXC_S_DMA_CFG_REQSEL_I2C1RX, ///< I2C1 Receive DMA Request Selection
69     MXC_DMA_REQUEST_SPI0TX = MXC_S_DMA_CFG_REQSEL_SPI0TX, ///< SPI0 Transmit DMA Request Selection
70     MXC_DMA_REQUEST_SPIMSSTX =
71         MXC_S_DMA_CFG_REQSEL_SPI1TX, ///< SPIMSS Transmit DMA Request Selection
72     MXC_DMA_REQUEST_UART0TX =
73         MXC_S_DMA_CFG_REQSEL_UART0TX, ///< UART0 Transmit DMA Request Selection
74     MXC_DMA_REQUEST_UART1TX =
75         MXC_S_DMA_CFG_REQSEL_UART1TX, ///< UART1 Transmit DMA Request Selection
76     MXC_DMA_REQUEST_I2C0TX = MXC_S_DMA_CFG_REQSEL_I2C0TX, ///< I2C0 Transmit DMA Request Selection
77     MXC_DMA_REQUEST_I2C1TX = MXC_S_DMA_CFG_REQSEL_I2C1TX, ///< I2C1 Transmit DMA Request Selection
78 
79     // Deprecated names
80     MXC_DMA_REQUEST_SPI1RX = MXC_S_DMA_CFG_REQSEL_SPI1RX, ///< SPI1 Receive DMA Request Selection
81     MXC_DMA_REQUEST_SPI1TX = MXC_S_DMA_CFG_REQSEL_SPI1TX, ///< SPI1 Transmit DMA Request Selection
82 } mxc_dma_reqsel_t;
83 
84 /** @brief Enumeration for the DMA prescaler */
85 typedef enum {
86     MXC_DMA_PRESCALE_DISABLE = MXC_S_DMA_CFG_PSSEL_DIS, ///< Prescaler disabled
87     MXC_DMA_PRESCALE_DIV256 = MXC_S_DMA_CFG_PSSEL_DIV256, ///< Divide by 256
88     MXC_DMA_PRESCALE_DIV64K = MXC_S_DMA_CFG_PSSEL_DIV64K, ///< Divide by 65,536
89     MXC_DMA_PRESCALE_DIV16M = MXC_S_DMA_CFG_PSSEL_DIV16M, ///< Divide by 16,777,216
90 } mxc_dma_prescale_t;
91 
92 /** @brief Enumeration for the DMA timeout value */
93 typedef enum {
94     MXC_DMA_TIMEOUT_4_CLK = MXC_S_DMA_CFG_TOSEL_TO4, ///< DMA timeout of 4 clocks
95     MXC_DMA_TIMEOUT_8_CLK = MXC_S_DMA_CFG_TOSEL_TO8, ///< DMA timeout of 8 clocks
96     MXC_DMA_TIMEOUT_16_CLK = MXC_S_DMA_CFG_TOSEL_TO16, ///< DMA timeout of 16 clocks
97     MXC_DMA_TIMEOUT_32_CLK = MXC_S_DMA_CFG_TOSEL_TO32, ///< DMA timeout of 32 clocks
98     MXC_DMA_TIMEOUT_64_CLK = MXC_S_DMA_CFG_TOSEL_TO64, ///< DMA timeout of 64 clocks
99     MXC_DMA_TIMEOUT_128_CLK = MXC_S_DMA_CFG_TOSEL_TO128, ///< DMA timeout of 128 clocks
100     MXC_DMA_TIMEOUT_256_CLK = MXC_S_DMA_CFG_TOSEL_TO256, ///< DMA timeout of 256 clocks
101     MXC_DMA_TIMEOUT_512_CLK = MXC_S_DMA_CFG_TOSEL_TO512, ///< DMA timeout of 512 clocks
102 } mxc_dma_timeout_t;
103 
104 /** @brief DMA transfer data width */
105 typedef enum {
106     /* Using the '_V_' define instead of the '_S_' since these same values will be used to
107        specify the DSTWD also.  The API functions will shift the value the correct amount
108        prior to writing the cfg register. */
109     MXC_DMA_WIDTH_BYTE = MXC_V_DMA_CFG_SRCWD_BYTE, ///< DMA transfer in bytes
110     MXC_DMA_WIDTH_HALFWORD = MXC_V_DMA_CFG_SRCWD_HALFWORD, ///< DMA transfer in 16-bit half-words
111     MXC_DMA_WIDTH_WORD = MXC_V_DMA_CFG_SRCWD_WORD, ///< DMA transfer in 32-bit words
112 } mxc_dma_width_t;
113 
114 /**
115  * @brief   The basic configuration information to set up a DMA channel
116  *          and prepare it for transfers.
117  *
118  */
119 typedef struct {
120     int ch; ///< The channel to load the configuration data into
121     mxc_dma_reqsel_t reqsel; ///< The request select line to be used (mem2mem, peripheral)
122     mxc_dma_width_t srcwd; ///< The source width (could be dependent on FIFO width)
123     mxc_dma_width_t dstwd; ///< The destination width (could be dependent on FIFO width)
124     int srcinc_en; ///< Whether to increment the source address during the transfer
125     int dstinc_en; ///< Whether to increment the source address during the transfer
126 } mxc_dma_config_t;
127 
128 /**
129  * @brief   The information needed to complete a DMA transfer
130  *
131  */
132 typedef struct {
133     int ch; ///< The channel to use for the transfer
134     void *source; ///< Pointer to the source address, if applicable
135     void *dest; ///< Pointer to the destination address, if applicable
136     int len; ///< Number of bytes to transfer
137 } mxc_dma_srcdst_t;
138 
139 /**
140  * @brief   The advanced configuration options, these are optional but could
141  *          be needed in cases where multiple DMA channels are running concurrently
142  *          or DMA is being used with low bandwidth peripherals.
143  *
144  */
145 typedef struct {
146     int ch; ///< The channel to use for the transfer
147     mxc_dma_priority_t prio; ///< The DMA priority for the channel
148     unsigned int reqwait_en; ///< Delay the timeout timer start until after first transfer
149     mxc_dma_timeout_t tosel; ///< Number of prescaled clocks seen by the channel before a timeout
150     mxc_dma_prescale_t pssel; ///< Prescaler for the timeout timer
151     unsigned int burst_size; ///< Number of bytes moved in a single burst
152 } mxc_dma_adv_config_t;
153 
154 /**
155  * @brief   The callback called on completion of a DMA_MemCpy() transfer
156  *
157  * @param   dest    Pointer to the destination of the copy
158  */
159 typedef void (*mxc_dma_complete_cb_t)(void *dest);
160 
161 /**
162  * @brief   The callback called on completion of a transfer,
163  * @note    This callback is used with MXC_DMA_DoTransfer()
164  *          to allow the user to chain an unlimited number of
165  *          DMA Transfers.
166  *
167  * @param   trans    Struct of the completed transfer
168  *
169  * @return  Returns the next transfer to be completed, or NULL
170  *          if no more transfers will be done
171  */
172 typedef mxc_dma_srcdst_t (*mxc_dma_trans_chain_t)(mxc_dma_srcdst_t dest);
173 
174 /* **** Function Prototypes **** */
175 /*************************/
176 /* Low Level Functions   */
177 /*************************/
178 /**
179  * @brief      Initialize DMA resources
180  * @details    This initialization is required before using the DMA driver functions.
181  * @note       On default this function enables DMA peripheral clock.
182  *             if you wish to manage clock and gpio related things in upper level instead of here.
183  *             Define MSDK_NO_GPIO_CLK_INIT flag in project.mk file.
184  *             By this flag this function will remove clock and gpio related codes from file.
185  * @return     #E_NO_ERROR if successful
186  */
187 int MXC_DMA_Init(void);
188 
189 /**
190  * @brief      De-Initialize DMA resources.
191  */
192 void MXC_DMA_DeInit(void);
193 
194 /**
195  * @brief      Request DMA channel
196  * @details    Returns a handle to the first free DMA channel, which can be used via API calls
197  *             or direct access to channel registers using the MXC_DMA_GetCHRegs(int ch) function.
198  * @return     Non-negative channel handle (inclusive of zero).
199  * @return     #E_NONE_AVAIL    All channels in use.
200  * @return     #E_BAD_STATE     DMA is not initialized, call MXC_DMA_Init() first.
201  * @return     #E_BUSY          DMA is currently busy (locked), try again later.
202  */
203 int MXC_DMA_AcquireChannel(void);
204 
205 /**
206  * @brief      Release DMA channel
207  * @details    Stops any DMA operation on the channel and returns it to the pool of free channels.
208  *
209  * @param          ch   channel handle to release
210  *
211  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
212  */
213 int MXC_DMA_ReleaseChannel(int ch);
214 
215 /**
216  * @brief      Configure the DMA channel
217  * @details    Configures the channel, which was previously requested by MXC_DMA_Getchannel()
218  *
219  * @param      config   Struct containing DMA configuration parameters
220  * @param      srcdst   Struct containing pointers and length of DMA operation
221  *
222  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
223  */
224 int MXC_DMA_ConfigChannel(mxc_dma_config_t config, mxc_dma_srcdst_t srcdst);
225 
226 /**
227  * @brief      Configure the DMA channel with more advanced parameters
228  *
229  * @param      advConfig    Struct containing advanced DMA parameters
230  *
231  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
232  */
233 int MXC_DMA_AdvConfigChannel(mxc_dma_adv_config_t advConfig);
234 
235 /**
236  * @brief      Set channel source, destination, and count for the transfer
237  * @param      srcdst Struct containing the channel, source, destination, and count for the channel
238  * @note       Unless the channel request select is #mxc_dma_srcdst_t = MXC_DMA_REQUEST_MEMTOMEM,
239  *             either src_addr or dst_addr will be ignored by the DMA engine.
240  *             In these cases, the address is a don't-care. See the User's
241  *             Guide for more information.
242  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
243  */
244 int MXC_DMA_SetSrcDst(mxc_dma_srcdst_t srcdst);
245 
246 /**
247  * @brief      Get channel source, destination, and count for transfer
248  *
249  * @param      srcdst Pointer to struct with the correct channel number
250  *
251  * @return     See \ref MXC_Error_Codes for a list of return values
252  */
253 int MXC_DMA_GetSrcDst(mxc_dma_srcdst_t *srcdst);
254 
255 /**
256  * @brief      Set channel reload source, destination, and count for the transfer
257  * @param      srcdstReload Struct containing the channel, source, destination, and count for the channel
258  * @note       Unless the channel request select is #mxc_dma_srcdst_t = MXC_DMA_REQUEST_MEMTOMEM,
259  *             either src_addr or dst_addr will be ignored by the DMA engine.
260  *             In these cases, the address is a don't-care. See the User's
261  *             Guide for more information.
262  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
263  */
264 int MXC_DMA_SetSrcReload(mxc_dma_srcdst_t srcdstReload);
265 
266 /**
267  * @brief      Get channel reload source, destination, and count for transfer
268  *
269  * @param      srcdstReload Pointer to struct with the correct channel number
270  *
271  * @return     See \ref MXC_Error_Codes for a list of return values
272  */
273 int MXC_DMA_GetSrcReload(mxc_dma_srcdst_t *srcdstReload);
274 
275 /**
276  * @brief      Set channel interrupt callback
277  * @param      ch        channel handle
278  * @param      callback  Pointer to a function to call when the channel
279  *                       interrupt flag is set and interrupts are enabled or
280  *                       when DMA is shutdown by the driver.
281  * @details    Configures the channel interrupt callback. The @p callback
282  *             function is called for two conditions:
283  *               -# When the channel's interrupt flag is set and DMA interrupts
284  *                  are enabled.
285  *               -# If the driver calls the MXC_DMA_Shutdown() function. The
286  *                  callback function prototype is:
287  * @code
288  *             void callback_fn(int ch, int reason);
289  * @endcode
290  *             @p ch indicates the channel that generated the callback, @p
291  *             reason is either #E_NO_ERROR for a DMA interrupt or #E_SHUTDOWN
292  *             if the DMA is being shutdown.
293  *
294  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR
295  *             otherwise
296  */
297 int MXC_DMA_SetCallback(int ch, void (*callback)(int, int));
298 
299 /**
300  * @brief      Set channel interrupt
301  * @note       Each channel has two interrupts (complete, and count to zero).
302  *             To enable complete, pass true for chdis. To enable count to zero,
303  *             pass true for ctz.
304  * @param      ch Channel Handle
305  * @param      chdis Enable channel complete interrupt
306  * @param      ctz Enable channel count to zero interrupt.
307  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
308  */
309 int MXC_DMA_SetChannelInterruptEn(int ch, bool chdis, bool ctz);
310 
311 /**
312  * @brief      Enable channel interrupt
313  * @note       Each channel has two interrupts (complete, and count to zero)
314                which must also be enabled with MXC_DMA_SetChannelInterruptEn()
315  * @param      ch   channel handle
316  * @param      flags The flags to enable
317  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
318  */
319 int MXC_DMA_ChannelEnableInt(int ch, int flags);
320 
321 /**
322  * @brief      Disable channel interrupt
323  * @param      ch   channel handle
324  * @param      flags The flags to disable
325  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
326  */
327 int MXC_DMA_ChannelDisableInt(int ch, int flags);
328 
329 /**
330  * @brief      Read channel interrupt flags
331  * @param      ch   channel handle
332  * @return     #E_BAD_PARAM if an unused or invalid channel handle, flags otherwise
333  */
334 int MXC_DMA_ChannelGetFlags(int ch);
335 
336 /**
337  * @brief      Clear channel interrupt flags
338  * @param      ch   channel handle
339  * @param      flags The flags to clear
340  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
341  */
342 int MXC_DMA_ChannelClearFlags(int ch, int flags);
343 
344 /**
345  * @brief      Enable channel interrupt
346  * @note       Each channel has two interrupts (complete, and count to zero)
347                which must also be enabled with MXC_DMA_SetChannelInterruptEn()
348  * @param      ch   channel handle
349  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
350  */
351 int MXC_DMA_EnableInt(int ch);
352 
353 /**
354  * @brief      Disable channel interrupt
355  * @param      ch   channel handle
356  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
357  */
358 int MXC_DMA_DisableInt(int ch);
359 
360 /**
361  * @brief      Start transfer
362  * @param      ch   channel handle
363  * @details    Start the DMA channel transfer, assumes that MXC_DMA_SetSrcDstCnt() has been called beforehand.
364  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
365  */
366 int MXC_DMA_Start(int ch);
367 
368 /**
369  * @brief      Stop DMA transfer, irrespective of status (complete or in-progress)
370  * @param      ch   channel handle
371  * @return     #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise
372  */
373 int MXC_DMA_Stop(int ch);
374 
375 /**
376  * @brief      Get a pointer to the DMA channel registers
377  * @param      ch   channel handle
378  * @details    If direct access to DMA channel registers is required, this
379  *             function can be used on a channel handle returned by MXC_DMA_AcquireChannel().
380  * @return     NULL if an unused or invalid channel handle, or a valid pointer otherwise
381  */
382 mxc_dma_ch_regs_t *MXC_DMA_GetCHRegs(int ch);
383 
384 /**
385  * @brief      Interrupt handler function
386  * @details    Call this function as the ISR for each DMA channel under driver control.
387  *             Interrupt flags for channel ch will be automatically cleared before return.
388  */
389 void MXC_DMA_Handler(void);
390 
391 /*************************/
392 /* High Level Functions  */
393 /*************************/
394 
395 /**
396  * @brief      Performs a memcpy, using DMA, optionally asynchronous
397  * @note       The user must have the DMA interrupt enabled and call
398  *             MXC_DMA_Handler() from the ISR.
399  *
400  * @param      dest     pointer to destination memory
401  * @param      src      pointer to source memory
402  * @param      len      number of bytes to copy
403  * @param      callback function to call when transfer is complete
404  *
405  * @return     see \ref MXC_Error_Codes
406  */
407 int MXC_DMA_MemCpy(void *dest, void *src, int len, mxc_dma_complete_cb_t callback);
408 
409 /**
410  * @brief      Performs a memcpy, using DMA, optionally asynchronous
411  * @note       The user must have the DMA interrupt enabled and call
412  *             MXC_DMA_Handler() from the ISR.
413  *
414  * @param      config   The channel config struct
415  * @param      firstSrcDst  The source, destination, and count for the first transfer
416  * @param      callback function is called when transfer is complete
417  *
418  * @return     see \ref MXC_Error_Codes
419  */
420 int MXC_DMA_DoTransfer(mxc_dma_config_t config, mxc_dma_srcdst_t firstSrcDst,
421                        mxc_dma_trans_chain_t callback);
422 /**
423  * For other functional uses of DMA (UART, SPI, etc) see the appropriate peripheral driver
424  */
425 
426 /**@} end of group dma */
427 #ifdef __cplusplus
428 }
429 #endif
430 
431 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32660_DMA_H_
432