Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef _FSL_DMA_H_
#define _FSL_DMA_H_

#include "fsl_common.h"

/*!
 * @addtogroup dma
 * @{
 */

/*! @file */
/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*! @name Driver version */
/*@{*/
/*! @brief DMA driver version */
#define FSL_DMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) /*!< Version 2.0.1. */
/*@}*/

#define DMA_MAX_TRANSFER_COUNT 0x400

#if defined FSL_FEATURE_DMA_NUMBER_OF_CHANNELS
#define FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(x) FSL_FEATURE_DMA_NUMBER_OF_CHANNELS
#define FSL_FEATURE_DMA_MAX_CHANNELS FSL_FEATURE_DMA_NUMBER_OF_CHANNELS
#define FSL_FEATURE_DMA_ALL_CHANNELS (FSL_FEATURE_DMA_NUMBER_OF_CHANNELS * FSL_FEATURE_SOC_DMA_COUNT)
#define FSL_FEATURE_DMA_DESCRIPTOR_ALIGN_SIZE (512)
#endif

/* Channel group consists of 32 channels. channel_group = (channel / 32) */
#define DMA_CHANNEL_GROUP(channel) (((uint8_t)(channel)) >> 5U)
/* Channel index in channel group. channel_index = (channel % 32) */
#define DMA_CHANNEL_INDEX(channel) (((uint8_t)(channel)) & 0x1F)

#define DMA_COMMON_REG_GET(base, channel, reg) \
    (((volatile uint32_t *)(&((base)->COMMON[0].reg)))[DMA_CHANNEL_GROUP(channel)])
#define DMA_COMMON_CONST_REG_GET(base, channel, reg) \
    (((volatile const uint32_t *)(&((base)->COMMON[0].reg)))[DMA_CHANNEL_GROUP(channel)])
#define DMA_COMMON_REG_SET(base, channel, reg, value) \
    (((volatile uint32_t *)(&((base)->COMMON[0].reg)))[DMA_CHANNEL_GROUP(channel)] = (value))

/*! @brief DMA descriptor structure */
typedef struct _dma_descriptor
{
    volatile uint32_t xfercfg; /*!< Transfer configuration */
    void *srcEndAddr;          /*!< Last source address of DMA transfer */
    void *dstEndAddr;          /*!< Last destination address of DMA transfer */
    void *linkToNextDesc;      /*!< Address of next DMA descriptor in chain */
} dma_descriptor_t;

/*! @brief DMA transfer configuration */
typedef struct _dma_xfercfg
{
    bool valid;             /*!< Descriptor is ready to transfer */
    bool reload;            /*!< Reload channel configuration register after
                                 current descriptor is exhausted */
    bool swtrig;            /*!< Perform software trigger. Transfer if fired
                                 when 'valid' is set */
    bool clrtrig;           /*!< Clear trigger */
    bool intA;              /*!< Raises IRQ when transfer is done and set IRQA status register flag */
    bool intB;              /*!< Raises IRQ when transfer is done and set IRQB status register flag */
    uint8_t byteWidth;      /*!< Byte width of data to transfer */
    uint8_t srcInc;         /*!< Increment source address by 'srcInc' x 'byteWidth' */
    uint8_t dstInc;         /*!< Increment destination address by 'dstInc' x 'byteWidth' */
    uint16_t transferCount; /*!< Number of transfers */
} dma_xfercfg_t;

/*! @brief DMA channel priority */
typedef enum _dma_priority
{
    kDMA_ChannelPriority0 = 0, /*!< Highest channel priority - priority 0 */
    kDMA_ChannelPriority1,     /*!< Channel priority 1 */
    kDMA_ChannelPriority2,     /*!< Channel priority 2 */
    kDMA_ChannelPriority3,     /*!< Channel priority 3 */
    kDMA_ChannelPriority4,     /*!< Channel priority 4 */
    kDMA_ChannelPriority5,     /*!< Channel priority 5 */
    kDMA_ChannelPriority6,     /*!< Channel priority 6 */
    kDMA_ChannelPriority7,     /*!< Lowest channel priority - priority 7 */
} dma_priority_t;

/*! @brief DMA interrupt flags */
typedef enum _dma_int
{
    kDMA_IntA,     /*!< DMA interrupt flag A */
    kDMA_IntB,     /*!< DMA interrupt flag B */
    kDMA_IntError, /*!< DMA interrupt flag error */
} dma_irq_t;

/*! @brief DMA trigger type*/
typedef enum _dma_trigger_type
{
    kDMA_NoTrigger = 0,                                                               /*!< Trigger is disabled */
    kDMA_LowLevelTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1) | DMA_CHANNEL_CFG_TRIGTYPE(1), /*!< Low level active trigger */
    kDMA_HighLevelTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1) | DMA_CHANNEL_CFG_TRIGTYPE(1) |
                            DMA_CHANNEL_CFG_TRIGPOL(1),    /*!< High level active trigger */
    kDMA_FallingEdgeTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1), /*!< Falling edge active trigger */
    kDMA_RisingEdgeTrigger =
        DMA_CHANNEL_CFG_HWTRIGEN(1) | DMA_CHANNEL_CFG_TRIGPOL(1), /*!< Rising edge active trigger */
} dma_trigger_type_t;

/*! @brief DMA trigger burst */
typedef enum _dma_trigger_burst
{
    kDMA_SingleTransfer = 0,                                /*!< Single transfer */
    kDMA_LevelBurstTransfer = DMA_CHANNEL_CFG_TRIGBURST(1), /*!< Burst transfer driven by level trigger */
    kDMA_EdgeBurstTransfer1 = DMA_CHANNEL_CFG_TRIGBURST(1), /*!< Perform 1 transfer by edge trigger */
    kDMA_EdgeBurstTransfer2 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(1), /*!< Perform 2 transfers by edge trigger */
    kDMA_EdgeBurstTransfer4 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(2), /*!< Perform 4 transfers by edge trigger */
    kDMA_EdgeBurstTransfer8 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(3), /*!< Perform 8 transfers by edge trigger */
    kDMA_EdgeBurstTransfer16 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(4), /*!< Perform 16 transfers by edge trigger */
    kDMA_EdgeBurstTransfer32 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(5), /*!< Perform 32 transfers by edge trigger */
    kDMA_EdgeBurstTransfer64 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(6), /*!< Perform 64 transfers by edge trigger */
    kDMA_EdgeBurstTransfer128 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(7), /*!< Perform 128 transfers by edge trigger */
    kDMA_EdgeBurstTransfer256 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(8), /*!< Perform 256 transfers by edge trigger */
    kDMA_EdgeBurstTransfer512 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(9), /*!< Perform 512 transfers by edge trigger */
    kDMA_EdgeBurstTransfer1024 =
        DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(10), /*!< Perform 1024 transfers by edge trigger */
} dma_trigger_burst_t;

/*! @brief DMA burst wrapping */
typedef enum _dma_burst_wrap
{
    kDMA_NoWrap = 0,                                /*!< Wrapping is disabled */
    kDMA_SrcWrap = DMA_CHANNEL_CFG_SRCBURSTWRAP(1), /*!< Wrapping is enabled for source */
    kDMA_DstWrap = DMA_CHANNEL_CFG_DSTBURSTWRAP(1), /*!< Wrapping is enabled for destination */
    kDMA_SrcAndDstWrap = DMA_CHANNEL_CFG_SRCBURSTWRAP(1) |
                         DMA_CHANNEL_CFG_DSTBURSTWRAP(1), /*!< Wrapping is enabled for source and destination */
} dma_burst_wrap_t;

/*! @brief DMA transfer type */
typedef enum _dma_transfer_type
{
    kDMA_MemoryToMemory = 0x0U, /*!< Transfer from memory to memory (increment source and destination) */
    kDMA_PeripheralToMemory,    /*!< Transfer from peripheral to memory (increment only destination) */
    kDMA_MemoryToPeripheral,    /*!< Transfer from memory to peripheral (increment only source)*/
    kDMA_StaticToStatic,        /*!< Peripheral to static memory (do not increment source or destination) */
} dma_transfer_type_t;

/*! @brief DMA channel trigger */
typedef struct _dma_channel_trigger
{
    dma_trigger_type_t type;   /*!< Select hardware trigger as edge triggered or level triggered. */
    dma_trigger_burst_t burst; /*!< Select whether hardware triggers cause a single or burst transfer. */
    dma_burst_wrap_t wrap;     /*!< Select wrap type, source wrap or dest wrap, or both. */
} dma_channel_trigger_t;

/*! @brief DMA transfer status */
enum _dma_transfer_status
{
    kStatus_DMA_Busy = MAKE_STATUS(kStatusGroup_DMA, 0), /*!< Channel is busy and can't handle the
                                                                transfer request. */
};

/*! @brief DMA transfer configuration */
typedef struct _dma_transfer_config
{
    uint8_t *srcAddr;      /*!< Source data address */
    uint8_t *dstAddr;      /*!< Destination data address */
    uint8_t *nextDesc;     /*!< Chain custom descriptor */
    dma_xfercfg_t xfercfg; /*!< Transfer options */
    bool isPeriph;         /*!< DMA transfer is driven by peripheral */
} dma_transfer_config_t;

/*! @brief Callback for DMA */
struct _dma_handle;

/*! @brief Define Callback function for DMA. */
typedef void (*dma_callback)(struct _dma_handle *handle, void *userData, bool transferDone, uint32_t intmode);

/*! @brief DMA transfer handle structure */
typedef struct _dma_handle
{
    dma_callback callback; /*!< Callback function. Invoked when transfer
                               of descriptor with interrupt flag finishes */
    void *userData;        /*!< Callback function parameter */
    DMA_Type *base;        /*!< DMA peripheral base address */
    uint8_t channel;       /*!< DMA channel number */
} dma_handle_t;

/*******************************************************************************
 * APIs
 ******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */

/*!
 * @name DMA initialization and De-initialization
 * @{
 */

/*!
 * @brief Initializes DMA peripheral.
 *
 * This function enable the DMA clock, set descriptor table and
 * enable DMA peripheral.
 *
 * @param base DMA peripheral base address.
 */
void DMA_Init(DMA_Type *base);

/*!
 * @brief Deinitializes DMA peripheral.
 *
 * This function gates the DMA clock.
 *
 * @param base DMA peripheral base address.
 */
void DMA_Deinit(DMA_Type *base);

/* @} */
/*!
 * @name DMA Channel Operation
 * @{
 */

/*!
* @brief Return whether DMA channel is processing transfer
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @return True for active state, false otherwise.
*/
static inline bool DMA_ChannelIsActive(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    return (DMA_COMMON_CONST_REG_GET(base, channel, ACTIVE) & (1U << DMA_CHANNEL_INDEX(channel))) ? true : false;
}

/*!
 * @brief Enables the interrupt source for the DMA transfer.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 */
static inline void DMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    DMA_COMMON_REG_GET(base, channel, INTENSET) |= 1U << DMA_CHANNEL_INDEX(channel);
}

/*!
 * @brief Disables the interrupt source for the DMA transfer.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 */
static inline void DMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    DMA_COMMON_REG_GET(base, channel, INTENCLR) |= 1U << DMA_CHANNEL_INDEX(channel);
}

/*!
 * @brief Enable DMA channel.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 */
static inline void DMA_EnableChannel(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    DMA_COMMON_REG_GET(base, channel, ENABLESET) |= 1U << DMA_CHANNEL_INDEX(channel);
}

/*!
 * @brief Disable DMA channel.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 */
static inline void DMA_DisableChannel(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    DMA_COMMON_REG_GET(base, channel, ENABLECLR) |= 1U << DMA_CHANNEL_INDEX(channel);
}

/*!
 * @brief Set PERIPHREQEN of channel configuration register.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 */
static inline void DMA_EnableChannelPeriphRq(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    base->CHANNEL[channel].CFG |= DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
}

/*!
 * @brief Get PERIPHREQEN value of channel configuration register.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 * @return True for enabled PeriphRq, false for disabled.
 */
static inline void DMA_DisableChannelPeriphRq(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    base->CHANNEL[channel].CFG &= ~DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
}

/*!
 * @brief Set trigger settings of DMA channel.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 * @param trigger trigger configuration.
 */
void DMA_ConfigureChannelTrigger(DMA_Type *base, uint32_t channel, dma_channel_trigger_t *trigger);

/*!
 * @brief Gets the remaining bytes of the current DMA descriptor transfer.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 * @return The number of bytes which have not been transferred yet.
 */
uint32_t DMA_GetRemainingBytes(DMA_Type *base, uint32_t channel);

/*!
 * @brief Set priority of channel configuration register.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 * @param priority Channel priority value.
 */
static inline void DMA_SetChannelPriority(DMA_Type *base, uint32_t channel, dma_priority_t priority)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    base->CHANNEL[channel].CFG =
        (base->CHANNEL[channel].CFG & (~(DMA_CHANNEL_CFG_CHPRIORITY_MASK))) | DMA_CHANNEL_CFG_CHPRIORITY(priority);
}

/*!
 * @brief Get priority of channel configuration register.
 *
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 * @return Channel priority value.
 */
static inline dma_priority_t DMA_GetChannelPriority(DMA_Type *base, uint32_t channel)
{
    assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(base));
    return (dma_priority_t)((base->CHANNEL[channel].CFG & DMA_CHANNEL_CFG_CHPRIORITY_MASK) >>
                            DMA_CHANNEL_CFG_CHPRIORITY_SHIFT);
}

/*!
 * @brief Create application specific DMA descriptor
 *        to be used in a chain in transfer
 *
 * @param desc DMA descriptor address.
 * @param xfercfg Transfer configuration for DMA descriptor.
 * @param srcAddr Address of last item to transmit
 * @param dstAddr Address of last item to receive.
 * @param nextDesc Address of next descriptor in chain.
 */
void DMA_CreateDescriptor(dma_descriptor_t *desc, dma_xfercfg_t *xfercfg, void *srcAddr, void *dstAddr, void *nextDesc);

/* @} */

/*!
 * @name DMA Transactional Operation
 * @{
 */

/*!
 * @brief Abort running transfer by handle.
 *
 * This function aborts DMA transfer specified by handle.
 *
 * @param handle DMA handle pointer.
 */
void DMA_AbortTransfer(dma_handle_t *handle);

/*!
 * @brief Creates the DMA handle.
 *
 * This function is called if using transaction API for DMA. This function
 * initializes the internal state of DMA handle.
 *
 * @param handle DMA handle pointer. The DMA handle stores callback function and
 *               parameters.
 * @param base DMA peripheral base address.
 * @param channel DMA channel number.
 */
void DMA_CreateHandle(dma_handle_t *handle, DMA_Type *base, uint32_t channel);

/*!
 * @brief Installs a callback function for the DMA transfer.
 *
 * This callback is called in DMA IRQ handler. Use the callback to do something after
 * the current major loop transfer completes.
 *
 * @param handle DMA handle pointer.
 * @param callback DMA callback function pointer.
 * @param userData Parameter for callback function.
 */
void DMA_SetCallback(dma_handle_t *handle, dma_callback callback, void *userData);

/*!
 * @brief Prepares the DMA transfer structure.
 *
 * This function prepares the transfer configuration structure according to the user input.
 *
 * @param config The user configuration structure of type dma_transfer_t.
 * @param srcAddr DMA transfer source address.
 * @param dstAddr DMA transfer destination address.
 * @param byteWidth DMA transfer destination address width(bytes).
 * @param transferBytes DMA transfer bytes to be transferred.
 * @param type DMA transfer type.
 * @param nextDesc Chain custom descriptor to transfer.
 * @note The data address and the data width must be consistent. For example, if the SRC
 *       is 4 bytes, so the source address must be 4 bytes aligned, or it shall result in
 *       source address error(SAE).
 */
void DMA_PrepareTransfer(dma_transfer_config_t *config,
                         void *srcAddr,
                         void *dstAddr,
                         uint32_t byteWidth,
                         uint32_t transferBytes,
                         dma_transfer_type_t type,
                         void *nextDesc);

/*!
 * @brief Submits the DMA transfer request.
 *
 * This function submits the DMA transfer request according to the transfer configuration structure.
 * If the user submits the transfer request repeatedly, this function packs an unprocessed request as
 * a TCD and enables scatter/gather feature to process it in the next time.
 *
 * @param handle DMA handle pointer.
 * @param config Pointer to DMA transfer configuration structure.
 * @retval kStatus_DMA_Success It means submit transfer request succeed.
 * @retval kStatus_DMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
 * @retval kStatus_DMA_Busy It means the given channel is busy, need to submit request later.
 */
status_t DMA_SubmitTransfer(dma_handle_t *handle, dma_transfer_config_t *config);

/*!
 * @brief DMA start transfer.
 *
 * This function enables the channel request. User can call this function after submitting the transfer request
 * or before submitting the transfer request.
 *
 * @param handle DMA handle pointer.
 */
void DMA_StartTransfer(dma_handle_t *handle);

/*!
 * @brief DMA IRQ handler for descriptor transfer complete.
 *
 * This function clears the channel major interrupt flag and call
 * the callback function if it is not NULL.
 */
void DMA_HandleIRQ(void);

/* @} */

#if defined(__cplusplus)
}
#endif /* __cplusplus */

/* @} */

#endif /*_FSL_DMA_H_*/