您好,欢迎访问三七文档
/*关于此分文档的说明:【目的】1.记录笔者对ARM的PL08x的DMA驱动PL08x.c理解。2.给其他不熟悉此DMA驱动的读者一点借鉴和参考。【适合读者】1.你已经具备一定驱动编程能力,知道一些最基本的概念,比如用于输出输出数据的设备的FIFO等,一般设备所具有的比如DATA等寄存器。2.希望对ARM的PL080的DMA驱动的工作流程有深入的了解,希望知道如何使用此DMA驱动。【声明】1.如果此文档中任何内容,侵犯了您的版权,涉及任何法律问题,请立即通知笔者,笔者会立即删除。2.如下代码,获取自:[RFCPATCH1/3]ARM:PL08X:AddadriverforthePL08xseriesofDMACcontrollers.水平有限,难免理解有误,欢迎指正和交流:green-waste(at)163.com*//*Copyright(c)2006ARMLtd.**Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit*underthetermsoftheGNUGeneralPublicLicenseaspublishedbytheFree*SoftwareFoundation;eitherversion2oftheLicense,or(atyouroption)*anylaterversion.**Thisprogramisdistributedinthehopethatitwillbeuseful,butWITHOUT*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor*moredetails.**YoushouldhavereceivedacopyoftheGNUGeneralPublicLicensealongwith*thisprogram;ifnot,writetotheFreeSoftwareFoundation,Inc.,59*TemplePlace-Suite330,Boston,MA02111-1307,USA.**ThefullGNUGeneralPublicLicenseisiinthisdistributioninthe*filecalledCOPYING.**Documentation:ARMDDI0196G==PL080*Documentation:ARMDDI0218E==PL081**//*上面两个文档,可以去ARM的主页下载到,具体地址是:PL080::下面用DDI0196表示此pl08x.cdma驱动对应的datasheet。【名词解释:datasheet】又称数据手册,是关于硬件资源,功能等详细描述的手册,是做相关驱动开发必不可少的资料,否则,你都不知道你的硬件能做什么事情,就没法去写对应的驱动了。【DMA简述】在开始分析代码之前,先简要介绍一下DMA的基础知识。1.什么是DMADMA,DirectMemoryAccess,直接内存访问。既然叫直接内存访问,那么相对应地,应该就有“间接的内存访问”。间接的内存访问,我的理解是,就是指最常见的,我们利用CPU的指令,去从一个内存地址中读出数据,然后写到另外一个内存地址中,完成对应的赋值操作。此过程,完全都是CPU去操作的,如果是单个这样的数据读取和写入,还没啥,但是如果数据量很大,比如我们用memcpy(addr1,addr2,1024)去从地址addr1地址开始,拷贝1024个字节到内存addr2处,那么CPU这段时间,就不要干别的事情了,就一直这么的给你读取,写入数据吧,另外的还有,常见于驱动中的,尤其是涉及到和外设打交道,我们让CPU从内存一个地址,读取了一个数据,然后写入到某个设备的FIFO或者DATA寄存器中,咋写入之前,常常会等待FIFO不是满的,然后才能写入数据,要从FIFO中读取数据,要等到FIFO不是空,才能读取,这样来来回回,会比较消耗资源。鉴于此,才出现了DMA这个硬件设备,专门设计用来处理这些相对用CPU去操作这样的事情,效率很低,换做专门的硬件的DMA来负责数据的读取和写入,释放了CPU这个苦力,可以让,在DMA忙着数据传输的过程中,CPU去忙其他更重要的事情。而专门的DMA硬件负责这样的数据传输,效率也会更高。之所以这样,才叫做内存直接访问的。2.DMA的一些基础概念DMA传输,总的来说就是,硬件上,会有对应的控制寄存器ctrl和配置寄存器config,比如你想要从内存一个地址addr传输,N个字word(32bit)的数据到设备dev上,那么你就要先去根据你的请求,去配置config寄存器,首先是传输方向,是DMA_TO_DEVICE,然后是源地址sourceaddress是你的内存地址addr,和目标destinationaddress是你的dev的DATA寄存器地址,然后要传输额transfersize是N个,每个位宽是32bit,将源地址,目标地址,位宽,DMA传输方向设置好,整理成一个结构,专有名称叫做LLI(LinkListItem),把这个LLi设置到ctrl里面。然后去enableDMA,DMA就可以按照你的要求,把数据传输过去了。这样的DMA叫做singleDMA传输,LLI中的nextlli的域设置为空,表示就一个LLI要传输。如果源地址或目标地址是多个分散的地址,叫做scatter/gatherDMA,就要将这些LLI组合一下,即将第一个LLI的nextlli那个域,设置成下一个LLI的地址,这样一个个链接起来,最后一个LLI的nexlli的域为空,这样设置好后,将第一个LLI的值写入到ctrl中,DMA就会自动地去执行第一个LLI的数据传输,传完后,发现nextlli不为空,就找到nextlli的位置,找到对应的配置,开始这个lli的数据传送,直至传完所有的数据为止。说完了DMA的由来和基本概念后,下面来分析一下,具体的ARM的PL08x驱动是如何实现的。*//**TheAMBADMAAPIismodelledontheISADMAAPIandperforms*singleasynchronoustransfersbetweenadeviceandmemory*i.e.someplatformfixeddeviceaddressandadriverdefinedmemoryaddress/*此AMBADMA驱动,基于ISADMA的API,好像应该就是那个DMAengine的架构吧,对应的,是这两个相关文件:\include\linux\dmaengine.h\drivers\dma\dmaengine.c主要实现了异步传输,细看内部实现,就是,你设置好所有的参数之后,就提交你的请求后,然后此dma驱动会去在合适的时候帮你实现你的dma请求。因此,不保证是立刻就去执行你的请求的,此之所以称作异步。正如上面的解释,常见的应用就是,对应某个外设有某个固定的设备地址,一般都是某个FIFO的地址,或者DATA之类的寄存器,然后你的DMA请求是,从内存某个地址传输一定数据到你这个设备的FIFO或者data寄存器,即往你设备里面写数据,或者相反,从你的设备的FIFO地址中,读取一定量数据到内存某个位置,即从你设备里面读取数据。*/**Memorytoperipheraltransfermaybevisualizedas*GetdatafrommemorytoDMAC*Untilnodataleft*Onburstrequestfromperipheral*DestinationburstfromDMACtoperipheral*Clearburstrequest*Raiseterminalcountinterrupt**ForperipheralswithaFIFO:*Sourceburstsize==halfthedepthoftheperipheralFIFO*Destinationburstsize==widthoftheperipheralFIFO/*关于提交DMA传输请求的时候,对于突发传输大小(burstsize)的设置,虽然此处建议对于sourceburstsize,设置成你的FIFO大小的一半,而对于destinationburstsize,设置为你的FIFO大小等同,但是,实际一般是根据你的外设控制器的设置而去具体设置的,比如你的nandflash控制器有个fifo是36个word,但是,其nandflashcontroller中关于burstsize的说明是,,DMA模式时候,当fifo中小于4个word并且将要写入数据大于32个word的时候,才会发送writeburst信号给dma,要求burst传输,期望一下子传输32个word,这样,一下子传输32个word,写入到nandflash的fifo里面,这样就比dma传输一次一个word,即singlewordtransfer的效率高多了。此时,你的destinationburstsize,就应该设置成32个word,之前,我以为也可以设置成16,8之类比32小的值,但是除了理论上理解的,没有充分利用硬件的能力、效率低之外,,实际上,驱动并不能正常工作,数据总是少不部分,就是说,硬件上人家有burst的dma请求了,就是已经准备了32个数据让你传,结果你只传输了部分,所以数据就少了一些,就乱了。一般来说,sourceburstsize,多数和destinationburstsize相等。具体,还要去看你的设备的datasheet。*/**(Burstsareirrelevantformemtomemtransfers-therearenoburstsignals)**Detailsofeachtranferonaparticularchannel*areheldintheDMAchannelarray*Aworkqueueusesthosedetailstoinitiatetheactualtransfer*TheDMACinterruptclearstherelevanttransferinthechannelarray**ASSUMESonlyoneDMACdeviceexistsinthesystem*ASSUMESdefault(little)endiannessforDMAtransfers**OnlyDMACflowcontrolisimplemented**/#includelinux/device.h#includelinux/init.h#includelinux/module.h#includelinux/pci.h#includelinux/interrupt.h#includelinux/workqueue.h#includelinux/dmapool.h#includeasm/dma.h#includeasm/mach/dma.h#includeasm/atomic.h#includeasm/processor.h#includelinux/amba/bus.h#includelinux/dmaengine.h#includeasm/cacheflush.h#inclu
本文标题:AMBADMA
链接地址:https://www.777doc.com/doc-658982 .html