Chinaunix首页 | 论坛 | 博客
  • 博客访问: 919571
  • 博文数量: 96
  • 博客积分: 10071
  • 博客等级: 上将
  • 技术积分: 1118
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-20 17:54
文章分类

全部博文(96)

文章存档

2011年(3)

2010年(3)

2009年(29)

2008年(54)

2007年(7)

分类: LINUX

2008-05-07 11:09:48

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的传输。
    
阅读(3345) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~