32.Linux-2440下的DMA驱动(详解)

转载请注解来源:http://www.cnblogs.com/zhanggui/p/6955742.html

DMA(Direct Memory Access)

二零一七年12月6日凌晨的138分钟,是属于WWDC2017的。

即直接存储器访问, DMA 传输模式无需 CPU
直接控制传输,通过硬件为 RAM 、I/O 设备开辟一条直接传送数据的通路,能使
CPU 的频率极为提升。

是因为时间问题,没有熬夜看,所以中午兴起趁着公司不太忙就看了看。全体的情节并未太多变化,依旧是苹果的主产品,不过这一次的one
more thing 是HomePod,如故挺令人可望的。


接下去自己将从大会的基本点内容和投机的感受多少个地点开展创作。这里只是简单的介绍,更多详情可以访问Apple.com翻开更多。

 

 

学了这样多驱动,不难推出DMA的编辑套路:

情节概览

  • 1)注册DMA中断,分配缓冲区
  • 2)注册字符设备,并提供文件操作集合fops
  •   ->
    2.1)file_operations里安装DMA硬件相关操作,来启动DMA

开场以小录像的方法发挥了苹果对人们通常生活的影响之大。AppStore
Server服务特别,导致人们的活着和办事等等各类方面都饱受了很大的影响。挺有意思的小录像,推荐我们观赏一下,很有新意。

出于大家是用字符设备的测试方法测试的,而本例子只是用多少个地点之间的正片来演示DMA的功用,所以接纳字符设备格局编写

然后就是库克(Cook)的开场,介绍了前些天登记开发者的食指:16
million;此次参加大会的人数:5300人;其中有大部分的学员开发者等等。这里还特别介绍了Yuma和Masaca:

 

图片 1

1.驱动编写之前,先来讲怎么着分配释放缓冲区、DMA相关寄存器介绍、使用DMA中断

Yuma来自澳大不莱梅,二〇一九年10岁,是苹果开发者中小小的的开发者。他从6岁起头编程,目前一度有5款app上架Appstore。另一位是来源于日本的82岁的Masako,到了老年才接触开发,自己也有一部分app上架AppStore。

1.1在linux中,分配释放DMA缓冲区,只能使用以下多少个函数

接下去就围绕了六点开班了本次WWDC的情节。这六点包括:

1) 

1.tvOS

/*该函数只禁止cache缓冲,保持写缓冲区,也就是对注册的物理区写入数据,也会更新到对应的虚拟缓存区上*/
void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); 
//分配DMA缓存区
//返回值为:申请到的DMA缓冲区的虚拟地址,若为NULL,表示分配失败,需要释放,避免内存泄漏
//参数如下:
  //*dev:指针,这里填0,表示这个申请的缓冲区里没有内容
  //size:分配的地址大小(字节单位)
  //*handle:申请到的物理起始地址
  //gfp:分配出来的内存参数,标志定义在<linux/gfp.h>,常用标志如下:
        //GFP_ATOMIC    用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
        //GFP_KERNEL    内核内存的正常分配. 可能睡眠.
      //GFP_USER      用来为用户空间页来分配内存; 它可能睡眠. 

2.Apple Watch

 

3.Mac

2)

4.iOS

/*该函数禁止cache缓存以及禁止写入缓冲区*/
void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);         
//分配DMA缓存区,返回值和参数和上面的函数一直

5.iPad

 

6.HomePod

 3)

接下去就简单介绍一下。

dma_free_writecombine(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle);   //释放DMA缓存,与dma_alloc_writecombine()对应
//size:释放长度
//cpu_addr:虚拟地址,
//handle:物理地址

 

 

01:tvOS

 4)

 

dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)    //释放DMA缓存,与dma_alloc_coherent ()对应
//size:释放长度
//cpu_addr:虚拟地址,
//handle:物理地址

紧要介绍了amazon来到了Apple 电视机。

 

图片 2 

 (PS:
dma_free_writecombine()其实就是dma_free_conherent(),只但是是用了#define重命名而已。)

图片 3

而我辈前边用的内存分配kmalloc()函数,是不可以用在DMA上,因为分红出来的内存可能在大体地址上是不总是的.

当前tvOS已经与50多家内容商合作,用户可以轻松收看自己喜爱的情节。同时,与Amazon合作,将来再Amazonvideo上看的始末都足以在tvOS上见到。

 

 

1.2
这就是说2440开发板咋样来启动DMA,先来看2440的DMA寄存器

02:Apple Watch

(PS:实际这个DMA相关的寄存器,在linux内核中Samsung已打包好了,可以直接调用,但是那些劳苦,还不如直接设置寄存器,能够参考:
http://blog.csdn.net/mirkerson/article/details/6632273
)

 

1.2.1
2440援助4个通道的DMA控制器

watchOS 4系统到来,包括了Siri
Face、Workout、Pool
Swim、和跑步机同步数据(利用NFC)、卡片布局等等。而且新增了三款玩具总动员人物表盘。 图片 4 图片 5

个中4个通道的DMA外设请求源,如下图所示(通过DCONn寄存器的[26:24]来设置)

图片 6

(PS:若是请求源是系统总线上的,就只需要设置DCONn寄存器的[23]=0即可)

下图是匡助NFC同步数据的厂商:

图片 7

图片 8

 

 

1.2.2
且每个通道都可以处理以下4种情状:

03:Mac

1)
源和对象都在系统总线上(比如:六个大体内存地址)
2)
当目的在外设总线上时,源在系统总线上(外设指:串口,定时器,I2C,I2S等)
3)
当目标在系统总线上时,源在外设总线上
4) 源和对象都在外设总线上

 

 

Mac紧要介绍了macOS High
Sierra
:

1.2.3
DMA有二种工作形式(通过DCONn寄存器的[28]来设置)

图片 9 

询问情势:

接受来说了Safari是社会风气上最快的桌面浏览器:

当DMA请求XnXDREQ为低电通常,则DMA会直接传输数据,直到DMA请求拉高,才打住

图片 10

拉手形式:

而且JavaScript perfromance比Chrom快80%:

当DMA请求XnXDREQ有下跌沿触发时,则DMA会传导三次数据

图片 11

 图片 12

 而且还拥有智能跟踪防御功用:

 

图片 13

1.2.4
DMA有两种传输格局(通过DCONn寄存器的[31]来设置)

还具有Autoplay Blocking功能。

单元传输:

还有Mail的Search Top Hits和Full-screen Split View:

指传输过程中,每执行三回,则读1次,写1次.(如上图所示)

图片 14

突发4传输:

图片 15

指传输过程中,每执行一遍,则读4次,然后写4次(如下图所示)

其余Photo的法力也更为强大,包括人脸识别和编制。尤其是图表的编撰功用:

 图片 16

图片 17

 

里头还拿PhotoShop CC做相比较。还包括了Metal 2和ML:

1.2.5
2440中的DMA寄存器如下图所示:

 图片 18

 图片 19

图片 20

 

再有特别为AR功效设计的的STEAM VR SDK:

共有4个通道的寄存器,且每个通道的寄存器内容都平等,所以我们以DMA通道0为例:

 图片 21

1)**DISRC0起先源寄存器 **

接下去是Mac的价钱:

[30:0]
: 存放DMA源的基地址

图片 22

2)**DISRCC0起先源控制寄存器**

图片 23

[1]
: 源地方选用,0:源在系统总线上,                      
1:源在外设总线上

还有新品:iMac Pro:

[0]
: 源地址拔取,0:传输时源地址自动扩张,          
 1:源地址固定

图片 24

3)DIDST0初叶目的寄存器

图片 25

[30:0]
: 设置DMA目标的基地址

图片 26

 

 期间还采取新的iMac显示了一款VR游戏,效果很逼真。在不久的今日,我们就能够使用STEAM
VR SDK举办VR开发。

4)DIDSTC0先导目的控制寄存器

 

[2]  :
中断时间采用,       0:当DMA传输计数=0,登时暴发中断      
1:执行完自动加载后再发送中断(也就是计数为0,然后再度加载计数值)

04:iOS

[1]
: 目标地方接纳,         0:目标在系统总线上,                     
   1:目标在外设总线上

 

[0]
: 目标地方拔取,         0:传输时目标地址自动扩大,         
  1:目的地址固定

首先就升级率和Android做了对待:

 

图片 27

5)DCON0控制寄存器

其实也得以知道,因为苹果系统唯有一家,而Android光国内就有红米、Samsung、酷派等等厂商,所以升级并不是google说升级就进步的。

[31]
: 工作格局采纳,   0:查询模式                  1:握手情势     (当源处于外设时,尽量挑选握手情势)

 接下来就是iOS11的介绍:

[30]
: 中断请求(DREQ)/中断回应(DACK)的协同时钟采取,       
0:PCLK同步     1:HCLK同步

席卷message同步iCloud、通过message举办转账、Apple Pay 的person to person
payment、siri更加智能、Camera高达两倍的压缩率,缩短占用空间、可以从Live
Photo得到指定的图片、重新定义Control
Center、siri的机器学习、map的室内导航以及速度限制和行车指南、Do Not
Disturb While Driving形式、Home基特使用Siri控制、airplay 2、新的AirPlay 2
audio API、Apple Music可以查看朋友正在听取的音乐、Music基特API等等。 图片 28

(PS:倘使有设施在HCLK上,该位应当设为1,比如:(SDRAM)内存数组,
反之当那一个装备在PCLK上,应当设为0,比如:ADC,IIS,I2C,UART)

图片 29

[29]
: DMA传输计数中断使能/禁止    
 0:禁止中断                               
1:当传输完成后,发生中断

图片 30 

[28]
: 传输情势拔取,
        0:单元传输                            1:突发4传输

此处也有国人一向关心的移动网络开关,也就是说可以不用打开设置,直接在Control
Center即可关闭移动数据网络。

[27]
: 传输服务情势  

接下去还介绍的崭新的也是世界上最好的App平台:AppStore:

0:单服务格局,比如:有2个DMA请求,它们会被逐一执行五回(单元传输/突发4传输)后停下,然后直到有下一遍DMA请求,再重新最先另五遍巡回。

图片 31

1:全服务格局,指该DMA若有请求,则会占用DMA总线,一贯传输,期间若有任何DMA请求,只有等待传输计数TC为0,才会举行此外DMA请求

周周有500 米尔(Mill)ion的访问量:

[26:24]
: DMA外设请求源选取

图片 32

[23]    
: 软件/硬件请求源拔取      0:软件请求     
      1:硬件请求(还亟需安装[26:24]来选取外设源)

 每一天180 比尔ion的下载量:

[22]    
: 重新加载开关选项             为0即可

图片 33

[21:20]
: 传输数据大小    为00(8位)即可

 还有70 Billion的Paid to Developers:

[19:0]  
: 设置DMA传输的计数TC               

图片 34

6)DSTAT0状态寄存器

 下边是全新Appstore实图:

[21:20]
:      DMA状态             00:空闲           01:忙

图片 35

[19:0]  
: 传输计数当前值CURR_TC            为0表示传输为止

图片 36

7)DCSRC0当前源寄存器

 其它还有Vision API:

[30:0]
 : 存放DMA当前的源基地址

图片 37

 

此地拿HUAWEI7和Google、三星做了一个对待:

8)DCDST0当前目标寄存器

图片 38

[30:0]
 : 存放DMA当前的目的基地址

 还有Augmented Reality:

 

图片 39

9)DMASKTRIG0触发屏蔽寄存器

图片 40

[2]   :
结束STOP            该位写1,顿时终止DMA当前的传导

图片 41 

[1]  
: DMA通道使能        0:关闭DMA的通道0(禁止DMA请求)           
1:开启DMA的通道0(开启DMA请求)

这边演示了一个Demo,可以从上图看到。

[0]  
: 软件请求触发   
  1:表示启动五遍软件请求DMA,只有DCONn[23]=0和DMASKTRIGn[1]=1才有效,DMA传输时,该位自动清0

还演示了Wingnut AR:

1.3接下去就起来讲linux注册DMA中断

图片 42

率先,DMA的每个通道只可以有一个源-
>目的,所以输入指令 cat
/proc/interrupts ,找到DMA3暂停未被使用

图片 43

所以在linux中使用:

very Fantastic!

request_irq(IRQ_DMA3, s3c_dma_irq, NULL, "s3c_dma", 1);// s3c_dma_irq:中断服务函数,这里注册DMA3中断服务函数
//NULL:中断产生类型, 不需要,所以填NULL
//1:表示中断时,传入中断函数的参数,本节不需要所以填1,切记不能填0,否则注册失败

再有专门为天朝设计的功能:

 

图片 44

 

可想而知iOS11中的VR是很值得我梦想的。

2.接下来,我们便来写一个DMA的字符设备驱动

 

步骤如下:

05:iPad

  • 1)
    注册DMA中断,分配六个DMA缓冲区(源、目标)
  • 2)
    注册字符设备,并提供文件操作集合fops
  • -> 2.1)
    通过ioctl的cmd来判断是使用DMA启动两个地方之间的正片,依旧一向六个地方之间的正片
  • ->
    2.2)倘诺DMA启动,则设置DMA的有关硬件,并启动DMA传输

 

2.1
所以,驱动代码如下所示:

三星平板这里就不多介绍了,直接看下边的图:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>   
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/dma-mapping.h>

#define  S3C_DMA_SIZE   512*1024          //DMA传输长度   512KB

#define NORMAL_COPY     0                 //两个地址之间的正常拷贝
#define DMA_COPY        1                 //两个地址之间的DMA拷贝

/*函数声明*/
static DECLARE_WAIT_QUEUE_HEAD(s3c_dma_queue);          //声明等待队列
static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long flags);

  /*
   * 定义中断事件标志
   * 0:进入等待队列        1:退出等待队列
   */
     static int s3c_dma_even=0;


static unsigned char   *source_virt;            //源虚拟地址
static unsigned int     source_phys;            //源物理地址

static unsigned char *dest_virt;              //目的虚拟地址
static unsigned int   dest_phys;              //目的虚拟地址


/*DMA3寄存器*/
struct  S3c_dma3_regs{
    unsigned int disrc3    ;          //0x4b0000c0
    unsigned int disrcc3   ;                    
    unsigned int didst3    ;                    
    unsigned int didstc3   ;               
    unsigned int dcon3     ;                
    unsigned int dstat3    ; 
    unsigned int dcsrc3    ; 
    unsigned int dcdst3    ;        
    unsigned int dmasktrig3;        //0x4b0000e0
};


 static volatile struct S3c_dma3_regs   *s3c_dma3_regs;

/*字符设备操作*/
static struct file_operations  s3c_dma_fops={
        .owner  = THIS_MODULE,
        .ioctl     = s3c_dma_ioctl,
};

/*中断服务函数*/
static irqreturn_t  s3c_dma_irq (int irq, void *dev_id)   
{
    s3c_dma_even=1;                             //退出等待队列
    wake_up_interruptible(&s3c_dma_queue);      //唤醒 中断
    return IRQ_HANDLED;
}

/*ioctl函数*/
static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long flags)
{
    int i;
    memset(source_virt, 0xAA, S3C_DMA_SIZE);          
    memset(dest_virt, 0x55, S3C_DMA_SIZE);   

    switch(cmd)
    {
    case NORMAL_COPY:                           //正常拷贝

             for(i=0;i<S3C_DMA_SIZE;i++)
                 dest_virt[i] =  source_virt[i];

             if(memcmp(dest_virt, source_virt, S3C_DMA_SIZE)==0)
           {
         printk("NORMAL_COPY OK\n");
                return 0;
         }
         else
        {
         printk("NORMAL_COPY ERROR\n");
               return -EAGAIN;
        }             

    case DMA_COPY:                               //DMA拷贝

        s3c_dma_even=0;     //进入等待队列

        /*设置DMA寄存器,启动一次DMA传输 */
        /* 源的物理地址 */
        s3c_dma3_regs->disrc3      = source_phys;      
        /* 源位于AHB总线, 源地址递增 */  
        s3c_dma3_regs->disrcc3     = (0<<1) | (0<<0);
        /* 目的的物理地址 */
        s3c_dma3_regs->didst3      = dest_phys;      
        /* 目的位于AHB总线, 目的地址递增 */
        s3c_dma3_regs->didstc3     = (0<<2) | (0<<1) | (0<<0);     
        /* 使能中断,单个传输,软件触发, */
        s3c_dma3_regs->dcon3=(1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(S3C_DMA_SIZE<<0);  
        //启动一次DMA传输
        s3c_dma3_regs->dmasktrig3  = (1<<1) | (1<<0);     

        wait_event_interruptible(s3c_dma_queue, s3c_dma_even);    //进入睡眠,等待DMA传输中断到来才退出

        if(memcmp(dest_virt, source_virt, S3C_DMA_SIZE)==0)
        {
         printk("DMA_COPY OK\n");
                return 0;
         }
        else
        {
       printk("DMA_COPY ERROR\n");
             return -EAGAIN;
           }  

            break;
    }
    return 0;
}


static unsigned int major;
static struct class *cls;
static int s3c_dma_init(void)
{
    /*1.1 注册DMA3 中断  */
    if(request_irq(IRQ_DMA3, s3c_dma_irq,NULL, "s3c_dma",1)) 
    {
        printk("Can't    request_irq   \"IRQ_DMA3\"!!!\n ");
        return -EBUSY;
    }

    /*1.2 分配两个DMA缓冲区(源、目的)*/
    source_virt=dma_alloc_writecombine(NULL,S3C_DMA_SIZE, &source_phys, GFP_KERNEL);
    if(source_virt==NULL)       
   {
        printk("Can't  dma_alloc   \n ");
        return -ENOMEM;
   }

    dest_virt=dma_alloc_writecombine(NULL,S3C_DMA_SIZE, &dest_phys, GFP_KERNEL);
    if(dest_virt==NULL)       
   {
        printk("Can't  dma_alloc   \n ");
        return -ENOMEM;
   }


    /*2.注册字符设备,并提供文件操作集合fops*/
    major=register_chrdev(0, "s3c_dma",&s3c_dma_fops);
    cls= class_create(THIS_MODULE, "s3c_dma");
    class_device_create(cls, NULL,MKDEV(major,0), NULL, "s3c_dma");

    s3c_dma3_regs=ioremap(0x4b0000c0, sizeof(struct S3c_dma3_regs));

    return 0;  
}

static void s3c_dma_exit(void)
{
    iounmap(s3c_dma3_regs);

    class_device_destroy(cls, MKDEV(major,0));
    class_destroy(cls);

    dma_free_writecombine(NULL, S3C_DMA_SIZE, dest_virt, dest_phys);
    dma_free_writecombine(NULL, S3C_DMA_SIZE, source_virt, source_phys);   

    free_irq(IRQ_DMA3, 1);

}
module_init(s3c_dma_init);
module_exit(s3c_dma_exit);
MODULE_LICENSE("GPL");

边框更窄:

2.2
应用测试程序如下所示:

图片 45

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>

/* ./dma_test NORMAL
 * ./dma_test DMA
 */
#define NORMAL_COPY     0               //两个地址之间的正常拷贝
#define DMA_COPY        1              //两个地址之间的DMA拷贝

void print_usage(char *name)
{
    printf("Usage:\n");
    printf("%s <NORMAL | DMA>\n", name);
}

int main(int argc, char **argv)
{
    int fd,i=30;

     if (argc != 2)
    {
        print_usage(argv[0]);
        return -1;
    }

    fd = open("/dev/s3c_dma", O_RDWR);
    if (fd < 0)
    {
        printf("can't open /dev/s3c_dma\n");
        return -1;
    }

    if (strcmp(argv[1], "NORMAL") == 0)
    {
        while (i--)                //调用驱动的ioctl(),30次
        {
            ioctl(fd, NORMAL_COPY);
        }
    }
    else if (strcmp(argv[1], "DMA") == 0)
    {
        while (i--)                //调用驱动的ioctl(),30次        
        {
            ioctl(fd, DMA_COPY);
        }
    }
    else
    {
        print_usage(argv[0]);
        return -1;
    }
    return 0;     
}

图片 46

3.测试运行

图片 47

输入
./dma_test NORMAL &
,使用CPU正常拷贝,可以发现占用了多数资源,输入 ls 无反应:

还有Apple Pencil:

 图片 48

图片 49

 

图片 50

输入./dma_test DMA & ,使用DMA拷贝,输入 ls 立马有感应,从而释放了CPU的下压力:

图片 51

 图片 52

图片 53

 

图片 54

 

图片 55

 

图片 56

 

多任务:

图片 57

New App Switcher:

图片 58

 Files:帮忙各样云:百度,微云等等。

图片 59

图片 60

图片 61

图片 62

 关于价格:

图片 63

接下去就是one more thing(乔布斯(乔布斯)),库克(Cook)叫它:one last thing:

 

06:HomePod

 

这次WWDC的压轴:

图片 64

价格:

图片 65

它的讲述可以用下边三句话概括:

1.Breakthrough home speaker

2.Spatial awareness

3.Musicologist

HomePod是一款效率强大的组合音响,听起来分外棒,适用于任哪个地方方。它与Apple
Music一起,可轻松访问世界上的音乐。而这所有的贯彻通过与Siri.1的本来语音交互举行说了算。它接纳无缝的3D网格覆盖,采纳了A8芯片,而且可以从多方位举办音乐广播和话音接收。

恐怕你会担心您和HomePod的对话被窃听,为了保障由此,苹果加密了对话的情节。

其一强大的喇叭也将在1二月在US、UK以及Australia发行。

以上便是本次大会的基本点内容。

 

感受

以下仅表示个人观点:

从这一次大会来看,苹果将会越加加强Siri的功能,让Siri更加强劲。

 

在智能家居方面,苹果也会愈来愈提高,这里的HomePod就是很好的例证。

 

其余,VR以后会更加火,苹果当然不情愿把那个蛋糕让给别人,自己一定要有所作为。STEAM
VR
SDK的面世以及WWDC下边对VR内容的牵线也充裕表达了这或多或少。VR值得期待,苹果在这一个样子已经开发发力。

 

指望苹果生产更多产品,让智能家居更加呈现。最好也能在天朝使用。

 

苹果的制品做得都很精妙,协理Apple。希望有更多的One more thing!