Platform: IMX6DL
OS: Android 4.4
Kernel branch: 3.0.35
1. 分配slave通道
#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param);
根据mask信息从系统中已经注册的dma list中找到一个符合条件的channel。static inline int dmaengine_slave_config(struct dma_chan *chan,
struct dma_slave_config *config);
配置slave的地址,方向,地址宽度等。struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
unsigned long flags);
或者struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
size_t period_len, enum dma_transfer_direction direction);
slave支持两种不同的传输方式 slave_sg 和 dma_cyclic,两者区别其实就是前者是全部传输完成产生中断,slave_sg
dma_cyclic
4. 提交DMA请求,等待处理完成回调通知。
static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc);
void (*device_issue_pending)(struct dma_chan *chan);
触发DMA无非就是使能DMA中断,然后开始传输,这一步也可以放到上一步的submit里处理。
处理完后会触发中断,然后回调函数会被调用。
IMX6DL的UART和Audio使用了DMA, 如下为Audio使用部分:
snd_imx_pcm_hw_params -> //imx-pcm-dma-mx2.c
imx_ssi_dma_alloc ->
dma_request_channel
dmaengine_slave_config
snd_imx_pcm_trigger -> //imx-pcm-dma-mx2.c
dmaengine_submit ->
desc->tx_submit ->
sdma_tx_submit ->
sdma_enable_channel
参考:
Documentation/dmaengine.txt