零: 介绍 之前一直没有接触过linux下的dma编程,总感觉很难很难,没敢接触过。最近公司事情少点   ,索性就了解了一下dma的编程,因为我对比较喜欢对寄存器进行操作 ,所以就以寄存器编程来说。 MT7688 generic DMA controller 在datasheet开篇就这样介绍: − Supports 16 DMA channels //支持16个信道   − Supports 32 bit address// 支持32位的地址 − Maximum 65535 byte transfer 最多支持65535字节的传输量  − Programmable DMA burst size (1, 2, 4, 8, 16 double word burst) 每次触发可以传输的双字数(双字单位) − Supports memory to memory, memory to peripheral, peripheral to memory, peripheral to peripheral transfers.//不用解释吧 − Supports continuous mode. − Supports division of target transfer count into 1 to 256 segments//每次传输可以最多分成256段 − Support for combining different channels into a chain.//上面说了一次数据最多传16双字也就是64字节   − Programmable hardware channel priority.                            //而数据传输可以最多分成256段 所以一个信道用− --Interrupts for each channel.                                                            //dma最多传16384字节的buffer大小。这里的一个                                                                                                                                    //chain估计可以装好几个channel 但是没用过!!!! 一:几个比较重要的寄存器。 对于每个channel都有四个寄存器进行描述。如下 其实也就是一个GDMA_SA_X一个GDMA_DA_X 两个控制寄存器GDMA_CT0_X   和 GDMA_CT1_X 1.1:GDMA_SA_X和GDMA_DA_X 这两个寄存器存放的是两个映射过后的物理地址,比如我使用dma是用的简单的mem to mem的功能,那么这两个地址是存放的我内存虚拟地址所对应的物理地址。 那问题来了?怎么确定对应的物理地址。 dst_vir = dma_alloc_coherent(NULL,100,&dst_phy,GFP_ATOMIC);//一致性映射 和流式映射关系不在此赘述 函数返回值dst_vir   就是向内存申请的100字节缓冲区的首地址。 100 缓冲区大小 dst_phy 申请下来的虚拟缓冲区dst_vir所对应的物理地址,这个 是申请的时候底层给的。 GFP_ATOMIC   这个是申请常用的符号 还有GFP_KERNEL  

1.2:GDMA_CT0_X 和GDMA_CT1_X 这两个寄存器比较麻烦主要就是初始化上面介绍的时候的东西。 CT0
截图已经给了 我就直接上我的对这两个寄存器操作的程序。 *reg_ct0 |=(0x01|0x01<<2|0x4<<3|0x100<<16); *reg_ct1 |=(Channel <<3|32<<8|32<<16); 三:dma中断的申请 request_irq(7,mydma_handler,IRQF_DISABLED,"mydma",NULL) 第一个是dma中断对应芯片的num号   mydma_handle 是处理函数 。。。。。。。 中断里面一般要做的东西是 1、清除中断 2、查看dma是否运行成功 3、返回 我的是这样处理的 static irqreturn_t mydma_handler(int irq, void *dev_id) { int i =0; *reg_int |=(0x01 << Channel);//清除中断   对应的channel 位写1就可 printk("in irq!\n"); for(i=0;i<100;i++) { printk("%2x ",dst_vir[i]); } printk("\n"); return   IRQ_HANDLED; } 全部的代码如下: #include #include #include #include #include #include #define DEVICE_NAME   "my_dma"
static dma_addr_t src_phy; static dma_addr_t dst_phy; static unsigned char* src_vir; static unsigned char* dst_vir; #define CMD_INIT_DMA      0x01 #define CMD_ENABLE_DMA   0x02
#define MY_DMA_BASE   0x10002800 #define Channel 0 unsigned long *reg_src,*reg_dst,*reg_ct0,*reg_ct1,*reg_int; void ralink_regset(unsigned myreg,int data) { myreg |= data; } static int ralink_dma_init(void) { int i = 0; *reg_src = src_phy; *reg_dst = dst_phy; *reg_ct0 |=(0x01|0x01<<2|0x4<<3|0x100<<16); *reg_ct1 |=(Channel <<3|32<<8|32<<16); *reg_int |=(0x01 << Channel); for(i=0;i<100;i++) { src_vir[i]=i; } return 0; } void ralink_dma_enable(void) {
*reg_ct0 |=(0x01 << 1); }
static long my_dma_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case CMD_INIT_DMA: ralink_dma_init(); break; case CMD_ENABLE_DMA: ralink_dma_enable(); break; default: break; }
return 0; }
struct file_operations my_dma = { .owner               = THIS_MODULE, .unlocked_ioctl = my_dma_ioctl, }; static irqreturn_t mydma_handler(int irq, void *dev_id) { int i =0; *reg_int |=(0x01 << Channel); printk("in irq!\n"); for(i=0;i<100;i++) { printk("%2x ",dst_vir[i]); } printk("\n"); return   IRQ_HANDLED; }
static int my_dma_init(void) { int result =   register_chrdev(888,DEVICE_NAME,&my_dma); if (result < 0) { printk("register failed!liujianlong \n"); return -1; } src_vir = dma_alloc_coherent(NULL,100,&src_phy,GFP_ATOMIC); if(src_vir == NULL) { unregister_chrdev(888, DEVICE_NAME); printk("src_vir is NULL!\n"); return -1; } dst_vir = dma_alloc_coherent(NULL,100,&dst_phy,GFP_ATOMIC); if(src_vir == NULL) { dma_free_coherent(NULL,100,src_vir,src_phy); unregister_chrdev(888, DEVICE_NAME); printk("dst_vir is NULL!\n"); return -1; } if(request_irq(7,mydma_handler,IRQF_DISABLED,"mydma",NULL)<0) { printk("request_irq failed!\n"); dma_free_coherent(NULL,100,src_vir,src_phy); dma_free_coherent(NULL,100,dst_vir,dst_phy); unregister_chrdev(888, DEVICE_NAME); return -1; } reg_src = (unsigned long*)ioremap(MY_DMA_BASE+Channel * 0x1f,4); if(reg_src == NULL) { printk("reg_src ioremap() failed!\n"); } reg_dst = (unsigned long*)ioremap(MY_DMA_BASE+Channel * 0x1f+0x04,4); if(reg_dst == NULL) { printk("reg_dst ioremap() failed!\n"); } reg_ct0 = (unsigned long*)ioremap(MY_DMA_BASE+Channel * 0x1f+0x08,4); if(reg_ct0 == NULL) { printk("reg_ct0 ioremap() failed!\n"); } reg_ct1 = (unsigned long*)ioremap(MY_DMA_BASE+Channel * 0x1f +0x0c,4); if(reg_ct1 == NULL) { printk("reg_ct1 ioremap() failed!\n"); } reg_int = (unsigned long*)ioremap(0x10002a04 ,4); if(reg_int == NULL) { printk("reg_int ioremap() failed!\n"); } printk("address map successfully!\n"); return 0; } static void my_dma_exit(void) { #if 1 dma_free_coherent(NULL,100,src_vir,src_phy); dma_free_coherent(NULL,100,dst_vir,dst_phy); #endif unregister_chrdev(888, DEVICE_NAME); iounmap(reg_ct0); iounmap(reg_ct1); iounmap(reg_dst); iounmap(reg_src); } module_init(my_dma_init); module_exit(my_dma_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Liu Long");

更多推荐

MT7688 的DMA编程memtomem实例