📄 dma.c
字号:
}/** * imx_dma_enable - function to start i.MX DMA channel operation * @dma_ch: i.MX DMA channel number * * The channel has to be allocated by driver through imx_dma_request() * or imx_dma_request_by_prio() function. * The transfer parameters has to be set to the channel registers through * call of the imx_dma_setup_single() or imx_dma_setup_sg() function * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to * be set prior this function call by the channel user. */void imx_dma_enable(imx_dmach_t dma_ch){ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; unsigned long flags; pr_debug("imxdma%d: imx_dma_enable\n", dma_ch); if (!imxdma->name) { printk(KERN_CRIT "%s: called for not allocated channel %d\n", __FUNCTION__, dma_ch); return; } local_irq_save(flags); DISR = (1 << dma_ch); DIMR &= ~(1 << dma_ch); CCR(dma_ch) |= CCR_CEN; local_irq_restore(flags);}/** * imx_dma_disable - stop, finish i.MX DMA channel operatin * @dma_ch: i.MX DMA channel number */void imx_dma_disable(imx_dmach_t dma_ch){ unsigned long flags; pr_debug("imxdma%d: imx_dma_disable\n", dma_ch); local_irq_save(flags); DIMR |= (1 << dma_ch); CCR(dma_ch) &= ~CCR_CEN; DISR = (1 << dma_ch); local_irq_restore(flags);}/** * imx_dma_request - request/allocate specified channel number * @dma_ch: i.MX DMA channel number * @name: the driver/caller own non-%NULL identification */int imx_dma_request(imx_dmach_t dma_ch, const char *name){ struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; unsigned long flags; /* basic sanity checks */ if (!name) return -EINVAL; if (dma_ch >= IMX_DMA_CHANNELS) { printk(KERN_CRIT "%s: called for non-existed channel %d\n", __FUNCTION__, dma_ch); return -EINVAL; } local_irq_save(flags); if (imxdma->name) { local_irq_restore(flags); return -ENODEV; } imxdma->name = name; imxdma->irq_handler = NULL; imxdma->err_handler = NULL; imxdma->data = NULL; imxdma->sg = NULL; local_irq_restore(flags); return 0;}/** * imx_dma_free - release previously acquired channel * @dma_ch: i.MX DMA channel number */void imx_dma_free(imx_dmach_t dma_ch){ unsigned long flags; struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; if (!imxdma->name) { printk(KERN_CRIT "%s: trying to free channel %d which is already freed\n", __FUNCTION__, dma_ch); return; } local_irq_save(flags); /* Disable interrupts */ DIMR |= (1 << dma_ch); CCR(dma_ch) &= ~CCR_CEN; imxdma->name = NULL; local_irq_restore(flags);}/** * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority * @dma_ch: i.MX DMA channel number * @name: the driver/caller own non-%NULL identification * @prio: one of the hardware distinguished priority level: * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW * * This function tries to find free channel in the specified priority group * if the priority cannot be achieved it tries to look for free channel * in the higher and then even lower priority groups. * * Return value: If there is no free channel to allocate, -%ENODEV is returned. * Zero value indicates successful channel allocation. */intimx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, imx_dma_prio prio){ int i; int best; switch (prio) { case (DMA_PRIO_HIGH): best = 8; break; case (DMA_PRIO_MEDIUM): best = 4; break; case (DMA_PRIO_LOW): default: best = 0; break; } for (i = best; i < IMX_DMA_CHANNELS; i++) { if (!imx_dma_request(i, name)) { *pdma_ch = i; return 0; } } for (i = best - 1; i >= 0; i--) { if (!imx_dma_request(i, name)) { *pdma_ch = i; return 0; } } printk(KERN_ERR "%s: no free DMA channel found\n", __FUNCTION__); return -ENODEV;}static irqreturn_t dma_err_handler(int irq, void *dev_id){ int i, disr = DISR; struct imx_dma_channel *channel; unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; int errcode; DISR = disr & err_mask; for (i = 0; i < IMX_DMA_CHANNELS; i++) { if(!(err_mask & (1 << i))) continue; channel = &imx_dma_channels[i]; errcode = 0; if (DBTOSR & (1 << i)) { DBTOSR = (1 << i); errcode |= IMX_DMA_ERR_BURST; } if (DRTOSR & (1 << i)) { DRTOSR = (1 << i); errcode |= IMX_DMA_ERR_REQUEST; } if (DSESR & (1 << i)) { DSESR = (1 << i); errcode |= IMX_DMA_ERR_TRANSFER; } if (DBOSR & (1 << i)) { DBOSR = (1 << i); errcode |= IMX_DMA_ERR_BUFFER; } /* * The cleaning of @sg field would be questionable * there, because its value can help to compute * remaining/transferred bytes count in the handler */ /*imx_dma_channels[i].sg = NULL;*/ if (channel->name && channel->err_handler) { channel->err_handler(i, channel->data, errcode); continue; } imx_dma_channels[i].sg = NULL; printk(KERN_WARNING "DMA timeout on channel %d (%s) -%s%s%s%s\n", i, channel->name, errcode&IMX_DMA_ERR_BURST? " burst":"", errcode&IMX_DMA_ERR_REQUEST? " request":"", errcode&IMX_DMA_ERR_TRANSFER? " transfer":"", errcode&IMX_DMA_ERR_BUFFER? " buffer":""); } return IRQ_HANDLED;}static irqreturn_t dma_irq_handler(int irq, void *dev_id){ int i, disr = DISR; pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", disr); DISR = disr; for (i = 0; i < IMX_DMA_CHANNELS; i++) { if (disr & (1 << i)) { struct imx_dma_channel *channel = &imx_dma_channels[i]; if (channel->name) { if (imx_dma_sg_next(i, CNTR(i))) { CCR(i) &= ~CCR_CEN; mb(); CCR(i) |= CCR_CEN; } else { if (channel->irq_handler) channel->irq_handler(i, channel->data); } } else { /* * IRQ for an unregistered DMA channel: * let's clear the interrupts and disable it. */ printk(KERN_WARNING "spurious IRQ for DMA channel %d\n", i); } } } return IRQ_HANDLED;}static int __init imx_dma_init(void){ int ret; int i; /* reset DMA module */ DCR = DCR_DRST; ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL); if (ret) { printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n"); return ret; } ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL); if (ret) { printk(KERN_CRIT "Wow! Can't register ERRIRQ for DMA\n"); free_irq(DMA_INT, NULL); } /* enable DMA module */ DCR = DCR_DEN; /* clear all interrupts */ DISR = (1 << IMX_DMA_CHANNELS) - 1; /* enable interrupts */ DIMR = (1 << IMX_DMA_CHANNELS) - 1; for (i = 0; i < IMX_DMA_CHANNELS; i++) { imx_dma_channels[i].sg = NULL; imx_dma_channels[i].dma_num = i; } return ret;}arch_initcall(imx_dma_init);EXPORT_SYMBOL(imx_dma_setup_single);EXPORT_SYMBOL(imx_dma_setup_sg);EXPORT_SYMBOL(imx_dma_setup_handlers);EXPORT_SYMBOL(imx_dma_enable);EXPORT_SYMBOL(imx_dma_disable);EXPORT_SYMBOL(imx_dma_request);EXPORT_SYMBOL(imx_dma_free);EXPORT_SYMBOL(imx_dma_request_by_prio);EXPORT_SYMBOL(imx_dma_channels);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -