DMA(三) - DMA控制器接口函数

DMA控制器接口函数

主要作用是配置DMA控制器并启动相应传输
s3c2440中关于公共DMA控制器的函数提供有:
s3c2410_dma_config()
s3c2410_dma_ctrl()
s3c2410_dma_enqueue()
s3c2410_dma_devconfig()
s3c2410_dma_set_buffdone_fn()
s3c2410_dma_request()
s3c2410_dma_free()
一般使用的顺序如下:
request =>set_buffdone_fn=> devconfig => config => enqueue => ctrl => free
1、int s3c2410_dma_request(unsigned int channel, struct s3c2410_dma_client *client, void *dev)

2、static inline void s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, enum s3c2410_dma_buffresult result)
设置相应的dma通道完成一次dma传输后的回调函数

3、int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source, unsigned long devaddr)
source: S3C2410_DMASRC_HW: source is hardware
S3C2410_DMASRC_MEM: source is memory
devaddr: physical addr of source

4、int s3c2410_dma_config(unsigned int channel, int xferunit)
根据xferunit设置通道的控制寄存器DCONx
xferunit为每次传输的数据大小:0:byte 1:half word 2:word

5、dma_alloc_coherent
DMA要求使用non-cached, 物理地址连续的内存。
将对应的内核虚拟地址转化为物理地址,供给后面的s3c2410_dma_enqueue函数使用。

6、int s3c2410_dma_enqueue(unsigned int channel, void *id, dma_addr_t data, int size)

7、int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
8、int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)

参考文章:
1. s3c2410的dma操作的一般步骤


DMA控制器接口函数使用实例

s3c2440 DMA datasheet

s3c2440 DMA控制器支持4种情况的DMA传输:
a. source and destination are in the system bus
b. source in the system bus while destination in the peripheral bus
c. source in the peripheral bus while destination in the system bus
d. source and destination are in the peripheral bus
但是在arch/arm/plat-s3c24xx/dma.c的函数s3c2410_dma_devconfig中却只实现了b和c两种情况。

s3c2440有4个DMA channel,每个channel都有DISC/DISCC/DIDST/DIDSTC寄存器,DISC和DIST可以填入不同source类型(具体参考S3c2440 Datasheet Table 8-1),除此之外还能填入内存的物理地址作为source或destination。

和传输相关的3个参数:
TSZ:DCON[28],0:unit模式:一次transfer1个data size,burst模式:一次transfer4个data size
DSZ:DCON[21:20],0:data size is BYTE,1:data size is Half WORLD,0:data size is WORLD
TC:DCON[19:0],transfer count
传输的数据量=TC * (DSZ * 8) * TSZ

request source: DCON[23]
0:S/W request mode, DMA is triggered by setting SW_TRIG bit of DMASKTRIG control register
1:DMA source selected by bit[26:24] triggers the DMA operation

service mode:DCON[27]
0:single service mode,一次DMA请求完成一次原子操作,等待下一次请求
1:whole service mode,一次DMA请求完成一批原子操作,当TC=0表示完成一次whole service

参考文章:
1. S3C2410:DMA介紹


使用cpu搬运内存与使用DMA搬运内存

下面这个例子我使用了s3c2440的公共DMA控制器,直接去配置寄存器并没有使用内核提供的arch/arm/plat-s3c24xx/dma.c文件中的DMA控制器接口函数,虽然效果是一样的,但最好应调用DMA控制器接口函数。
完整代码位置:dma_operation.c

static ssize_t s3c_mem_copy_store(struct device *dev,
                        struct device_attribute *attr,
                        const char *buf, size_t count)
{
    int i;
    unsigned long time_s = 0, time_e = 0;

    if (!buf && count < 1)
        return -1;

    printk("buf is: %s", buf);

    memset(s3c_dma_dev->src, 0xaa, BUF_SIZE);
    memset(s3c_dma_dev->dst, 0x55, BUF_SIZE);

    switch (buf[0]) {
    case MEM_CPY_NO_DMA:
        time_s = jiffies;
        for(i = 0;i < BUF_SIZE;i++)
            s3c_dma_dev->dst[i] = s3c_dma_dev->src[i];
        time_e  = jiffies;

        if (memcmp(s3c_dma_dev->src, s3c_dma_dev->dst, BUF_SIZE) == 0)
            printk("MEM_CPY_NO_DMA OK\n");
        else
            printk("MEM_CPY_NO_DMA ERROR\n");
        break;
    case MEM_CPY_DMA:
        s3c_dma_dev->dma_regs->disrc = s3c_dma_dev->src_phy;        //src physical addr
        s3c_dma_dev->dma_regs->disrcc = (0 << 1) | (0 << 0);            //src in the AHB bus, addr INC 
        s3c_dma_dev->dma_regs->didst = s3c_dma_dev->dst_phy;        //dst physical addr
        s3c_dma_dev->dma_regs->didstc = (0 << 2) | (0 << 1) | (0 << 0); //intr when TC=0, dst in AHB bus, addr INC
        s3c_dma_dev->dma_regs->dcon = (1 << 30) | (1 << 29) | (0 << 28) | (1 << 27) \
                | (0 << 23) | (0 << 20) | (BUF_SIZE << 0);      // enable intr, unit mode, soft trig

        /* start DMA transfer */
        time_s = jiffies;
        s3c_dma_dev->dma_regs->dmasktrig = (1 << 1) | (1 << 0);
        wait_for_completion(&s3c_dma_dev->comp);
        time_e  = jiffies;

        if (memcmp(s3c_dma_dev->src, s3c_dma_dev->dst, BUF_SIZE) == 0)
            printk("MEM_CPY_DMA OK\n");
        else
            printk("MEM_CPY_DMA ERROR\n");

        break;

    default:
        break;
    }

    printk("use time: %ld\n", time_e - time_s);
    return count;
}
static DEVICE_ATTR(oper, 0666, NULL, s3c_mem_copy_store);

static irqreturn_t s3c_dma_irq(int irq, void *devid)
{
    complete(&s3c_dma_dev->comp);

    return IRQ_HANDLED;
}

参考文章:
1. S3C实现DMA驱动程序编写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luckywang1103

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值