linux下的2440的DMA使用介绍
creator
sz111@126.com
前天完成了UDA1341的驱动,程序是网上下载的,仅仅小改一下而已,昨晚上
分析了其中的DMA部分,有些小小的感想,如果不正确希望读者能够告诉我。谢谢。
写的很乱,没有整理。
DMA的基础就不介绍了,可以参考http://blog.chinaunix.net/u1/58640/showart_483567.html
和规格书。我主要根据audio的使用,介绍一下DMA的使用。
1.首先对DMA进行初始化。
如对outstream的初始化
channel = 2;
source = S3C2410_DMASRC_MEM;//源地址为Memory
hwcfg = 3;
devaddr = 0x55000010;
dcon = 0xa0800000;
flags = S3C2410_DMAF_AUTOSTART;
/* s3c2410_dma_devconfig
*
* configure the dma source/destination hardware type and address
* 配置DMA的源和目的的硬件类型和地址
* source: S3C2410_DMASRC_HW: source is hardware 源是硬件
* S3C2410_DMASRC_MEM: source is memory 源是内存
*
* hwcfg: the value for xxxSTCn register,
* bit 0: 0=increment pointer, 1=leave pointer
* bit 1: 0=soucre is AHB, 1=soucre is APB
*
* devaddr: physical address of the source
*/
因为我们的DMA 源是内存,目的是硬件IIS的固定地址,所以hwcfg应该
设定为APB FIX_ADDR 即:3
int s3c2410_dma_devconfig(int channel,
s3c2410_dmasrc_t source,
int hwcfg,
unsigned long devaddr)
{
s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
check_channel(channel);
pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
__FUNCTION__, (int)source, hwcfg, devaddr);
chan->source = source;
chan->dev_addr = devaddr;
switch (source) {
case S3C2410_DMASRC_HW:
/* source is hardware */
pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
__FUNCTION__, devaddr, hwcfg);
dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
return 0;
case S3C2410_DMASRC_MEM:
/* source is memory */
pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
__FUNCTION__, devaddr, hwcfg);
dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
return 0;
}
printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
return -EINVAL;
}
/* s3c2410_dma_config
*
* xfersize: size of unit in bytes (1,2,4)
* dcon: base value of the DCONx register
*/
dcon = 0xa0800000;
因为IIS是16bit的,所以unit为2.
s3c2410_dma_config(channel, 2, dcon);
//设定DMA传输结束后的回调函数
s3c2410_dma_set_buffdone_fn(channel, audio_dmaout_done_callback);
//设定S3C2410_DMAF_AUTOSTART
s3c2410_dma_setflags(channel, flags);
//申请DMA通道
ret = s3c2410_dma_request(s->dma_ch, &s3c2410iis_dma_out, NULL);
以上是初始化部分,之后通过dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL);
来申请缓冲,dmabuf为虚拟地址,dmaphys是物理地址,虚拟地址用来让驱动写buf用,dmaphys用来传给dma。
dma关心的是实际的物理地址。
然后通过s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, b->size);来启动dma传输,
这里面的参数就是dmaphys,它为实际地址。
如果dma传输结束,就会调用:
static void audio_dmaout_done_callback(s3c2410_dma_chan_t *ch, void *buf, int size,
s3c2410_dma_buffresult_t result)
{
audio_buf_t *b = (audio_buf_t *) buf;
DPRINTK("audio_dmaout_done_callback\n");
up(&b->sem);
wake_up(&b->sem.wait);
}
来启动下一个buf的传输。
来源:http://blog.chinaunix.net/u1/49088/showart_679760.html
阅读(2015) | 评论(0) | 转发(0) |