SEP4020 Linux DMA驱动编写心得及使用流程

SEP4020 DMA驱动编写心得及使用流程
照例,一个驱动写完后要记录点东西,日后有问题绝对是珍贵的参考资料。

前两天看了s3c2410的linux dma驱动,写的很巧妙,我们的SEP4020也有必要编写一个专用的DMA驱动程序。
SEP4020以前的驱动中,在使用DMA时(如nand、iis、sd、usb)都是在驱动中各自配置,一般使用while循环来等待DMA传输完成。
这种方法实现功能没有问题,但是因为一直要等待传输完成,感觉完全没有利用DMA不经过CPU的优点。
专用DMA驱动程序,就是要解决这个问题,实现DMA列队,其他驱动使用DMA时只要调用DMA驱动,将需要发送缓冲区丢入DMA列队,就可以执行其他代码了。

花了几天时间终于按照2410的驱动写完了SEP4020的Linux DMA驱动,记录下SEP4020需要注意的几个问题:
(1)SEP4020有六个DMA通道,但是共用一个中断控制器的中断号(IRQ30),需要在中断处理程序中读取DMA控制器对应的中断位,判断是那个DMA通道引起的中断。
正是因为共用中断,所以前期写的代码各自使用DMA时都没有使用中断,怕驱动之间打架。
也正因为共用中断,注册中断的任务就不再放在request_dma_channel中,而是放在init函数中执行。

(2)s3c2410的DMA有个很好用的功能,可以自动加载,只需要再加载前改写source地址和传输大小即可。
DMA驱动中也使用了自动加载功能,一般在loadbuf函数后DMA即可自动开始下次传输。
SEP4020可没有自动加载buf功能,因此需要手动启动DMA传输。具体的做法实在loadbuf之后执行start函数。
sep4020_dma_loadbuffer(chan, chan->next);
sep4020_dma_ctrl(chan->number, SEP4020_DMAOP_START);

(3)同样是由于没有自动加载功能,SEP4020在DMA传输完成后就自动停止,不需要修改寄存器手动来停止。
所以s3c2410驱动中的dostop函数就没用了。

(4)每次传输开始时要重新写一遍control寄存器,不知道什么原因,configuration寄存器就不需要重写。
也可能我测试的不够,我是用IIS-UDA1341进行测试的,每次启动前要重写一遍control寄存器才能出声音。

(5)DMA使用devconfig函数进行配置,config函数没有使用。需要配置内容如下:
A source是硬件还是memory
B dest地址
C contorl寄存器
D configuration寄存器(不启动)

(6)DMA start函数的作用实际就是将对应通道的configuration寄存器的最后一位置1,启动传输。

(7)2410在传输时如果load状态处于loaded_running时,需要等待传输完成再load缓冲区。
SEP4020传输完成后直接进中断,并清除了传输完成位,所以无法判断。
我将相关超时等待函数注释掉,暂时没有发现问题,可能还需要全面考虑。

好,就记录以上几点,状态机使用s3c2410的,没有改变。
这个DMA驱动终于可以实现IIS播放MP3直接从nand上读取数据,不会再卡了!

当然DMA驱动程序还存在一定局限性:只能实现硬件到内存或者内存到硬件的传输,也就是启动一个地址是固定的,另外一个地址不断变化。

=======================================================
附录:SEP4020 DMA驱动使用流程(以IIS为例)

1)初始化结构体成员
static struct sep4020_dma_client sep4020_uda1341 = 
{
    .name = "sep4020_uda1341",
};

2)完成回调函数(参考)
static void uda1341_dma_done_callback(sep4020_dma_chan_t *ch, void *buf, int size,sep4020_dma_buffresult_t result)
{
   printk("uda1341_dma_done_callback\n");
   audio_buf_t *b = (audio_buf_t *) buf;
   up(&b->sem); 
   wake_up(&b->sem.wait);
}

3)初始化IIS驱动时,申请DMA通道
sep4020_dma_request(CHANNEL1, &sep4020_uda1341, NULL);

4)设置DMA传输完成回调函数
sep4020_dma_set_buffdone_fn(CHANNEL1, uda1341_dma_done_callback);

5)配置DMA通道参数
sep4020_dma_setflags(CHANNEL1, SEP4020_DMAF_AUTOSTART);//这个函数基本没用了
sep4020_dma_devconfig(CHANNEL1, SEP4020_DMASRC_MEM, destadd, ctrl, conf);
稍微解释下:
SEP4020_DMASRC_MEM:说明source是memory
destadd:既然source定了,传入dest的地址
ctrl:控制寄存器
conf:配置寄存器
寄存器请参考SEP4020数据手册

6)建立buf缓冲区,可以参考uda1341驱动中的audio_setup_buf函数
dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL|GFP_DMA);
关键在与使用dma_alloc_coherent申请连续空间(不会被cache),获取虚拟地址及物理地址,DMA寄存器需要赋值物理地址。

7)发起DMA传输
sep4020_dma_enqueue(CHANNEL1, (void *) b, b->dma_addr, b-size);
其中b是缓冲区,b->dma_addr是物理地址,b->size是大小(暂时没有实现,大小在devconfig函数配置)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值