⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma_systems.html

📁 ADI 公司blackfin系列的用户使用文挡。
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head>  <title></title>  <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />  <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />  <link rel="stylesheet" media="print" type="text/css" href="./print.css" />  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><a href=start.html>start</a></br><div class="toc"><div class="tocheader toctoggle" id="toc__header">Table of Contents</div><div id="toc__inside"><ul class="toc"><li class="clear"><ul class="toc"><li class="level2"><div class="li"><span class="li"><a href="#dma_systems" class="toc">DMA Systems</a></span></div></li><li class="level2"><div class="li"><span class="li"><a href="#linux_dma" class="toc">Linux DMA</a></span></div><ul class="toc"><li class="level3"><div class="li"><span class="li"><a href="#ok_whats_a_bus_address" class="toc">Ok Whats a Bus address ?</a></span></div></li></ul></li><li class="level2"><div class="li"><span class="li"><a href="#blackfin_dma" class="toc">Blackfin DMA</a></span></div><ul class="toc"><li class="level3"><div class="li"><span class="li"><a href="#simple_dma_example" class="toc">Simple DMA Example</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#flow_types" class="toc">Flow Types</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#descriptors" class="toc">Descriptors</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#descriptor_memory_layout" class="toc">Descriptor Memory Layout</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#descriptor_api" class="toc">Descriptor API</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#x_and_y_values" class="toc">X and Y Values</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#dma_priority" class="toc">DMA Priority</a></span></div></li></ul></li></ul></li></ul></div></div><h2><a name="dma_systems" id="dma_systems">DMA Systems</a></h2><div class="level2"><p> There are two aspects of the DMA subsystem to consider.</p><ul><li class="level1"><div class="li"> The built in Linux DMA interface</div></li><li class="level1"><div class="li"> The extensions for the Blackfin</div></li></ul><p> These two will be covered in different sections.</p></div><!-- SECTION [1-205] --><h2><a name="linux_dma" id="linux_dma">Linux DMA</a></h2><div class="level2"><p> This is closely related to the needs for DMA processes on mainly x86 systems but also provides a base set of DMA functions that apply to non x86 systems.</p><p>Most of the x86 complexity is a result from dealing with hardware capabilities. With a Memory Management Unit and Data Caches you have the problem of providing a memory area that  is valid for the io device dma processor and also valid for the CPU as well as making sure that when data arrives in the memory the CPU will not be looking at invalid cached data instead.</p><p>This sort of memory mapping is called consistent ( sometimes coherent ). In some architectures a coherent mapping implies some quite clever arrangement where the data is always valid even if cached. It is possible, with a memory management unit to provide two (or more) virtual addresses for the same physical memory area. One virtual address will pass through the Data Cache and while cached will not look at physical memory location, another virtual address will reference the same physical memory location but will bypass the cache altogether.</p><p>Another complication in x86 systems is the limitation on some early IO Hardware being unable to access physical memory areas greater than 16M. This causes the Linux memory allocation system to have to allow a special memory allocation option to restrict physical memory to the lower 16M of memory (GFP DMA).   Since this restriction was also passed on to hardware devices used in other architectures the memory allocation schemes in these architectures had to have similar options.</p><p>The Microcontroller and DSP fields are, in the main, free of these restrictions but , since the aim of the kernel programmer is to be architecture independent you have to know about these &ldquo;features&rdquo;.</p><p>So first, the <strong>generic</strong> Linux DMA <acronym title="Application Programming Interface">API</acronym> (there are more) </p><ul><li class="level1"><div class="li"> request_dma(unsigned int chan, const char * device_id)</div></li><li class="level1"><div class="li"> free_dma(unsigned int chan)</div></li><li class="level1"><div class="li"> enable_dma ( int chan)</div></li><li class="level1"><div class="li"> disable_dma ( int chan )</div></li><li class="level1"><div class="li"> set_dma_addr(unsigned int chan, unsigned int addr)</div></li><li class="level1"><div class="li"> set_dma_count(unsigned int chan, unsigned int count)</div></li></ul><p> Looking at an example driver <strong>linux-2.6.x/drivers/net/3c505.c</strong></p><pre class="code c">     <span class="co1">// try to get an irq </span>     <span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>retval = request_irq<span class="br0">&#40;</span>dev-&gt;irq, &amp;elp_interrupt, <span class="nu0">0</span>, dev-&gt;name, dev<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>          printk<span class="br0">&#40;</span>KERN_ERR <span class="st0">"%s: could not allocate IRQ%d<span class="es0">\n</span>"</span>, dev-&gt;name, dev-&gt;irq<span class="br0">&#41;</span>;          <span class="kw1">return</span> retval;     <span class="br0">&#125;</span>     <span class="co1">// OK now get a DMA channel</span>     <span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>retval = request_dma<span class="br0">&#40;</span>dev-&gt;dma, dev-&gt;name<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>          free_irq<span class="br0">&#40;</span>dev-&gt;irq, dev<span class="br0">&#41;</span>;          printk<span class="br0">&#40;</span>KERN_ERR <span class="st0">"%s: could not allocate DMA%d channel<span class="es0">\n</span>"</span>, dev-&gt;name, dev-&gt;dma<span class="br0">&#41;</span>;          <span class="kw1">return</span> retval;    <span class="br0">&#125;</span>&nbsp;    <span class="co1">// we have an irq and a dma channel got get some memory</span>    adapter-&gt;dma_buffer = <span class="br0">&#40;</span><span class="kw4">void</span> *<span class="br0">&#41;</span> dma_mem_alloc<span class="br0">&#40;</span>DMA_BUFFER_SIZE<span class="br0">&#41;</span>;&nbsp;    <span class="co1">// if this fails free up the resources and report an error</span>    <span class="kw1">if</span> <span class="br0">&#40;</span>!adapter-&gt;dma_buffer<span class="br0">&#41;</span> <span class="br0">&#123;</span>          printk<span class="br0">&#40;</span>KERN_ERR <span class="st0">"%s: could not allocate DMA buffer<span class="es0">\n</span>"</span>, dev-&gt;name<span class="br0">&#41;</span>;          free_dma<span class="br0">&#40;</span>dev-&gt;dma<span class="br0">&#41;</span>;          free_irq<span class="br0">&#40;</span>dev-&gt;irq, dev<span class="br0">&#41;</span>;          <span class="kw1">return</span> -ENOMEM;     <span class="br0">&#125;</span></pre><p>Once a dma channel has been grabbed and memory allocated the buffer can be used as shown.</p><pre class="code c">  <span class="co1">// if copy data to buffer if out of range</span>&nbsp;  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">long</span><span class="br0">&#41;</span><span class="br0">&#40;</span>skb-&gt;data + nlen<span class="br0">&#41;</span> &gt;= MAX_DMA_ADDRESS || nlen != skb-&gt;len<span class="br0">&#41;</span> <span class="br0">&#123;</span>                memcpy<span class="br0">&#40;</span>adapter-&gt;dma_buffer, skb-&gt;data, nlen<span class="br0">&#41;</span>;                memset<span class="br0">&#40;</span>adapter-&gt;dma_buffer+skb-&gt;len, <span class="nu0">0</span>, nlen-skb-&gt;len<span class="br0">&#41;</span>;                target = isa_virt_to_bus<span class="br0">&#40;</span>adapter-&gt;dma_buffer<span class="br0">&#41;</span>;        <span class="br0">&#125;</span>        <span class="kw1">else</span> <span class="br0">&#123;</span>                target = isa_virt_to_bus<span class="br0">&#40;</span>skb-&gt;data<span class="br0">&#41;</span>;        <span class="br0">&#125;</span>        adapter-&gt;current_dma.<span class="me1">skb</span> = skb;&nbsp;        <span class="co1">// target is now the dma physical ( or bus ) address</span>&nbsp;        <span class="co1">// lock and fire off the DMA</span>        flags=claim_dma_lock<span class="br0">&#40;</span><span class="br0">&#41;</span>;        disable_dma<span class="br0">&#40;</span>dev-&gt;dma<span class="br0">&#41;</span>;        clear_dma_ff<span class="br0">&#40;</span>dev-&gt;dma<span class="br0">&#41;</span>;        set_dma_mode<span class="br0">&#40;</span>dev-&gt;dma, 0x48<span class="br0">&#41;</span>;   <span class="coMULTI">/* dma memory -&gt; io */</span>        set_dma_addr<span class="br0">&#40;</span>dev-&gt;dma, target<span class="br0">&#41;</span>;        set_dma_count<span class="br0">&#40;</span>dev-&gt;dma, nlen<span class="br0">&#41;</span>;        outb_control<span class="br0">&#40;</span>adapter-&gt;hcr_val | DMAE | TCEN, dev<span class="br0">&#41;</span>;        enable_dma<span class="br0">&#40;</span>dev-&gt;dma<span class="br0">&#41;</span>;</pre></div><!-- SECTION [206-4238] --><h3><a name="ok_whats_a_bus_address" id="ok_whats_a_bus_address">Ok Whats a Bus address ?</a></h3><div class="level3"><p> When the CPU (say with the MMU turned off) wants to access Physical memory it puts that address on its output pins.  This a <strong>Physical Address</strong>.</p><p>When a peripheral device wants to access the same physical memory ( as in a DMA function ) it may have to use a different address to get to the same physical location. This is a <strong>Bus Address</strong>.</p></div><!-- SECTION [4239-4617] --><h2><a name="blackfin_dma" id="blackfin_dma">Blackfin DMA</a></h2><div class="level2"><p> The Blackfin has a much extended DMA capability. </p><ul><li class="level1"><div class="li"> 12 Different DMA channels</div></li><li class="level1"><div class="li"> Memory to Memory and IO to Memory Channels</div></li><li class="level1"><div class="li"> Dual X and Y indexing Address counters</div></li><li class="level1"><div class="li"> Simple Register Dma control</div></li><li class="level1"><div class="li"> Optional Sophisticated Descriptor Based Control </div></li><li class="level1"><div class="li"> 8,16 or 32 bit data size</div></li><li class="level1"><div class="li"> Interrupt on each DMA packet completion</div></li><li class="level1"><div class="li"> Flexible DMA Priority</div></li></ul><p> The <acronym title="Application Programming Interface">API</acronym> has been extended to allow for the increased flexibility </p><ul><li class="level1"><div class="li"> request_dma(unsigned int channel, const char *device_id, dma_callback_t callback);</div></li><li class="level1"><div class="li"> new_request_dma(unsigned int channel, const char *device_id, dma_callback_t callback, DMA_TYPE dma_type);</div></li><li class="level1"><div class="li"> freedma(unsigned int channel);</div></li><li class="level1"><div class="li"> set_dma_descriptor_base(unsigned int channel, unsigned int base);</div></li><li class="level1"><div class="li"> disable_dma(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma(unsigned int channel);</div></li><li class="level1"><div class="li"> set_dma_addr(unsigned int channel, unsigned long addr);</div></li><li class="level1"><div class="li"> set_dma_dir(unsigned int channel, char dir);</div></li><li class="level1"><div class="li"> set_dma_type(unsigned int channel, char type);</div></li><li class="level1"><div class="li"> set_dma_x_count(unsigned int channel, unsigned short x_count);</div></li><li class="level1"><div class="li"> set_dma_y_count(unsigned int channel, unsigned short y_count);</div></li><li class="level1"><div class="li"> set_dma_x_modify(unsigned int channel, unsigned short x_modify);</div></li><li class="level1"><div class="li"> set_dma_y_modify(unsigned int channel, unsigned short y_modify);</div></li><li class="level1"><div class="li"> set_dma_config(unsigned int channel, unsigned short config);</div></li><li class="level1"><div class="li"> set_dma_next_desc_addr(unsigned int channel, unsigned long next_desc_addr);</div></li><li class="level1"><div class="li"> set_dma_transfer_size(unsigned int channel, char size);</div></li><li class="level1"><div class="li"> get_dma_transfer_size(unsigned int channel, unsigned short *size);</div></li><li class="level1"><div class="li"> enable_dma_stopmode(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma_autobuffer(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma_descr_array(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma_descr_small(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma_descr_large(unsigned int channel);</div></li><li class="level1"><div class="li"> get_dma_curr_x_count(unsigned int channel, unsigned short *x_count);</div></li><li class="level1"><div class="li"> clear_dma_buffer(unsigned int channel);</div></li><li class="level1"><div class="li"> disable_dma_buffer_clear(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma_data_row_intr(unsigned int channel);</div></li><li class="level1"><div class="li"> enable_dma_data_intr(unsigned int channel);</div></li><li class="level1"><div class="li"> disable_dma_data_row_intr(unsigned int channel);</div></li><li class="level1"><div class="li"> disable_dma_data_intr(unsigned int channel);</div></li><li class="level1"><div class="li"> dma_get_irq_stat(unsigned int channel, unsigned short *irq_stat);</div></li></ul></div><!-- SECTION [4618-6839] --><h3><a name="simple_dma_example" id="simple_dma_example">Simple DMA Example</a></h3><div class="level3"><p> This is a simple DMA example taken from the <code>adsp-spidac.c</code> driver. This is getting 8 bit data from the SPI device int mybuffer.</p><pre class="code c"><span class="kw4">int</span> mydmatest<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -