linux-2.6.24.4中s3c2410和dma有关的函数的分析

发布者:电子设计艺术家最新更新时间:2022-05-25 来源: eefocus关键字:linux  s3c2410  dma 手机看文章 扫描二维码
随时随地手机看文章

首先介绍s3c2410与DMA相关的寄存器


s3c2410共有4通道的dma,每通道9个寄存器,共36个。

 

    1、DISRCn 该寄存器保存待传送数据的源地址。
    2、DISRCCn 源控制寄存器。位1表示数据源的总线类型,位0表示地址是否自动增减。
    3、DIDSTn 该寄存器保存待传送数据的目的地址。
    4、DIDSTCn 目的控制寄存器。位1表示目的地址的总线类型,位0表示地址是否自动增减。
    5、DCON  DMA控制寄存器。
    6、DSTATn DMA状态寄存器。
    7、DCSRCn 当前源地址寄存器
    8、DCDSTn 当前目的地址寄存器。
    9、DMASKTRIGn DMA MASK寄存器。

 

 

下面是linux-2.6.24.4中和dma有关的函数的分析:

 

首先定义了几个变量:
static int dma_channels ;//被设定为4
static struct s3c24xx_dma_selection dma_sel ;
struct s3c2410_dma_chan s3c2410_chans [S3C2410_DMA_CHANNELS];
static struct s3c24xx_dma_order * dma_order ;


有关的结构体定义如下:

struct s3c24xx_dma_selection {

 struct s3c24xx_dma_map * map ;

 unsigned long map_size;

 unsigned long dcon_mask;

 void ( * select ) ( struct s3c2410_dma_chan * chan,

     struct s3c24xx_dma_map * map ) ;

} ;


struct s3c24xx_dma_map {

 const char * name;

 struct s3c24xx_dma_addr hw_addr;

 unsigned long channels[ S3C2410_DMA_CHANNELS] ;

} ;


struct s3c2410_dma_chan {

 /* channel state flags and information * /

 unsigned char number; /* number of this dma channel * /

 unsigned char in_use; /* channel allocated * /

 unsigned char irq_claimed; /* irq claimed for channel * /

 unsigned char irq_enabled; /* irq enabled for channel * /

 unsigned char xfer_unit; /* size of an transfer * /

 /* channel state * /

 enum s3c2410_dma_state state;

 enum s3c2410_dma_loadst load_state;

 struct s3c2410_dma_client * client;

 /* channel configuration * /

 enum s3c2410_dmasrc source;

 unsigned long dev_addr;

 unsigned long load_timeout;

 unsigned int flags; /* channel flags * /

 struct s3c24xx_dma_map * map; /* channel hw maps * /

 /* channel


struct s3c24xx_dma_order {

 struct s3c24xx_dma_order_ch channels[ DMACH_MAX] ;

} ;


struct s3c24xx_dma_order_ch {

 unsigned int list [ S3C2410_DMA_CHANNELS] ; /* list of channels */

 unsigned int flags; /* flags */

} ;


 


然后分析各个函数。


int s3c2410_dma_request( unsigned int channel,

   struct s3c2410_dma_client * client,

   void * dev)

{

 struct s3c2410_dma_chan * chan;

 unsigned long flags;

 int err;

 pr_debug( "dma%d: s3c2410_request_dma: client=%s, dev=%p/n" ,

   channel, client- > name, dev) ;

 local_irq_save( flags) ;

 chan = s3c2410_dma_map_channel( channel) ; //获得dma通道


 if ( chan = = NULL ) {

  local_irq_restore( flags) ;

  return - EBUSY;

 }

 dbg_showchan( chan) ;

 chan- > client = client;

 chan- > in_use = 1; //占用该dma通道


 if ( ! chan- > irq_claimed) {

  pr_debug( "dma%d: %s : requesting irq %d/n" ,

    channel, __FUNCTION__ , chan- > irq) ;

  chan- > irq_claimed = 1;

  local_irq_restore( flags) ;

  err = request_irq( chan- > irq, s3c2410_dma_irq, IRQF_DISABLED, //申请中断


      client- > name, ( void * ) chan) ;

  local_irq_save( flags) ;

  if ( err) { //中断申请失败


   chan- > in_use = 0; //释放申请的通道和其他资源


   chan- > irq_claimed = 0;

   local_irq_restore( flags) ;

   printk( KERN_ERR "%s: cannot get IRQ %d for DMA %d/n" ,

          client- > name, chan- > irq, chan- > number) ;

   return err;

  }

  chan- > irq_enabled = 1; //使能中断


 }

 local_irq_restore( flags) ;

 /* need to setup */

 pr_debug( "%s: channel initialised, %p/n" , __FUNCTION__ , chan) ;

 return 0;

}


 

可见,该函数向内核申请了资源,即dma通道,然后就可以对申请的通道进行设置了。下面继续。

 

int s3c2410_dma_config( dmach_t channel, //通道号,和申请时使用的通道号要一致


         int xferunit, //发送时位的设置,可以是1、2、或者4,分别对应8、16和32位方式


         int dcon) //特别重要,就是dcon寄存器的值


{

 struct s3c2410_dma_chan * chan = lookup_dma_channel( channel) ; //得到申请的dma通道


 pr_debug( "%s: chan=%d, xfer_unit=%d, dcon=%08x/n" ,

   __FUNCTION__ , channel, xferunit, dcon) ;

 if ( chan = = NULL )

  return - EINVAL;

 pr_debug( "%s: Initial dcon is %08x/n" , __FUNCTION__ , dcon) ;

 dcon | = chan- > dcon & dma_sel. dcon_mask; //这步的作用是清除dcon寄存器中除了24~26的其他位,从datasheet中知道这三位


      //决定dma的中断源


 pr_debug( "%s: New dcon is %08x/n" , __FUNCTION__ , dcon) ;

 switch ( xferunit) { //设置字节传送的方式


 case 1:

  dcon | = S3C2410_DCON_BYTE;

  break ;

 case 2:

  dcon | = S3C2410_DCON_HALFWORD;

  break ;

 case 4:

  dcon | = S3C2410_DCON_WORD;

  break ;

 default :

  pr_debug( "%s: bad transfer size %d/n" , __FUNCTION__ , xferunit) ;

  return - EINVAL;

 }

 dcon | = S3C2410_DCON_HWTRIG; //使24~26位的选择有效


 dcon | = S3C2410_DCON_INTREQ; //使传送完成的时候产生中断


 pr_debug( "%s: dcon now %08x/n" , __FUNCTION__ , dcon) ;

 chan- > dcon = dcon;

 chan- > xfer_unit = xferunit;

 return 0;

}


由以上分析可以知道,该函数完成的主要功能就是设置对应通道的dcon寄存器。关于更细节的东西,可以查看datasheet。


int s3c2410_dma_devconfig( int channel,

     enum s3c2410_dmasrc source, //dma传送源的类型,可以是S3C2410_DMASRC_HW和S3C2410_DMASRC_MEM


     int hwcfg,

     unsigned long devaddr) //传送的目的地址


{

 struct s3c2410_dma_chan * chan = lookup_dma_channel( channel) ;

 if ( chan = = NULL )

  return - EINVAL;

 pr_debug( "%s: source=%d, hwcfg=%08x, devaddr=%08lx/n" ,

   __FUNCTION__ , ( int ) source, hwcfg, devaddr) ;

 chan- > source = source;

 chan- > dev_addr = devaddr;

 switch ( source) {

 case S3C2410_DMASRC_HW: //dma传送源是外围硬件


  /* source is hardware */

  pr_debug( "%s: hw source, devaddr=%08lx, hwcfg=%d/n" ,

    __FUNCTION__ , devaddr, hwcfg) ;

  dma_wrreg( chan, S3C2410_DMA_DISRCC, hwcfg & 3) ; //设置源控制寄存器


  dma_wrreg( chan, S3C2410_DMA_DISRC, devaddr) ; //设置传送源的地址


  dma_wrreg( chan, S3C2410_DMA_DIDSTC, ( 0< < 1) | ( 0< < 0) ) ; //目的地址一般是内存


  chan- > addr_reg = dma_regaddr( chan, S3C2410_DMA_DIDST) ; //得到传送目的地址寄存器的地址


  return 0;

 case S3C2410_DMASRC_MEM: //dma传送源是内存


  /* source is memory */

  pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d/n" ,

     __FUNCTION__ , devaddr, hwcfg) ;

  dma_wrreg( chan, S3C2410_DMA_DISRCC, ( 0< < 1) | ( 0< < 0) ) ; //传送源控制器


  dma_wrreg( chan, S3C2410_DMA_DIDST, devaddr) ; //传送的目的地址


  dma_wrreg( chan, S3C2410_DMA_DIDSTC, hwcfg & 3) ; //目的地址控制器


  chan- > addr_reg = dma_regaddr( chan, S3C2410_DMA_DISRC) ; //得到传送源地址寄存器的地址


  return 0;

 }

 printk( KERN_ERR "dma%d: invalid source type (%d)/n" , channel, source) ;

 return - EINVAL;

}


 


整个系统中dma的建立过程如下:


首先调用了s3c2410_dma_init(),该函数只有一句:

return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);

其中第一个参数就是通道号,第二个参数为dma的中断号的基数,第三个参数表示各个通道占用的空间的大小。

在函数s3c24xx_dma_init中,主要做了以下几件事情:

1、调用ioremap,将dma控制器的地址做一个映射。

2、为dma分配内核空间。

3、将上面提到的s3c2410_chans数组的内容全部清零。

4、初始化4个s3c2410_dma_chan结构的变量,对其中的一部分成员赋值。

成功结束时,该函数返回0。

 

 

第二步,系统调用s3c24xx_dma_order_set函数,如下:

s3c24xx_dma_order_set(&s3c2410_dma_order);

s3c2410_dma_order定义于arch/arm/mach-s3c2410/dma.c文件中,是一个s3c24xx_dma_order类型的结构体。

该函数主要为该结构体分配空间,然后将s3c2410_dma_order的内容copy到dma_order中。

 

 

第三步,系统调用s3c24xx_dma_init_map,完成dma通道的映射:

return s3c24xx_dma_init_map(&s3c2410_dma_sel);

下面重点分析一下该函数。

传给该函数的参数定义如下:

 

static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {

 . select = s3c2410_dma_select,

 . dcon_mask = 7 < < 24,

 . map = s3c2410_dma_mappings,

 . map_size = ARRAY_SIZE( s3c2410_dma_mappings) ,

} ;


该函数首先为各个通道分配内存空间,分配的总的大小为sizeof(struct s3c24xx_dma_map ) * s3c2410_dma_sel.map_size。


然后,函数把s3c2410_dma_sel的所有内容全部赋给上面提到的dma_sel结构体,该结构体就包含了所有的dma可以申请的通道。


用户申请dma通道的时候,内核就可以在dma_sel的map表中查找,并决定是否可以使用该dma通道。


关键字:linux  s3c2410  dma 引用地址:linux-2.6.24.4中s3c2410和dma有关的函数的分析

上一篇:s3c2410_i2c总线驱动及at24c02设备驱动实例
下一篇:linux 2.6.24.4在S3C2410上的移植(CS8900网卡驱动)(基于GEC2410)

推荐阅读最新更新时间:2024-11-10 11:54

STM32F429的LTDC和DMA2D
STM32F429与之前的系列强大之处就在于增加了LTDC个功能,从手册上看STM32F429的LTDC可以用于驱动1024x768分辨率的LCD屏幕。 LTDC其实就是TFT LCD控制器的意思,在arm9/arm11/cortex-A系列CPU当中,这个是必须有的外设,在小型单片机中,有这个功能的不多。 LCD控制器的功能就是生成LCD像素时钟,将GRAM中的数据搬运到LCD屏幕上去显示。 在一般的小型LCD模块一般都集成了一个LCD控制器,如常用的ili9320/ili9325等型号,这些LCD模块同时还集成了几百KB大小的RAM,用于显示; 这种方案,不需要占用单片机的RAM就可以稳定地驱动LCD显示图像,一般
[单片机]
大神教你如何快速使用DMA处理ADC
ADC: 1.STM32内部的ADC模块有三个ADC1,ADC2,ADC3,他们彼此独立,所以可以进行同步采样。 2ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生,要在RCC_CFGR配置,再ADC自己的寄存器中在没有时钟分频的配置位。 3.ADC转换时间: STM32F103xx增强型产,时钟为56MHz时为1μ s( 时钟为72MHz为1.17 μ s) 4.ADC的转换精度默认设置为12位,输入范围:ADC输入范围:V REF-≤ VIN≤ VREF+ 5.共有18个通道,其中外部16个通道,内部两个通道,内部温度传感器连接在ADC1_IN16,内部参考电压V REFINT连接在ADC1_IN17 6
[单片机]
大神教你如何快速使用<font color='red'>DMA</font>处理ADC
(linux自学笔记)linux内核定时器的使用
很显然linux的内核定时器基于时钟节拍(和ucos一样)。ucos的时钟节拍可由void OS_CPU_SysTickInit (INT32U cnts)函数设置。在linux中,时钟节拍在param.h中定义。 timer驱动程序 #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/poll.h #include linux/irq.h #include asm/irq.h #include linux/i
[单片机]
(<font color='red'>linux</font>自学笔记)<font color='red'>linux</font>内核定时器的使用
Linux发明者痛批英特尔芯片设计
据外媒报道,对于近期闹得沸沸扬扬的芯片漏洞事件,Linux OS的发明者Linus Torvalds表示有话要说了,他表示,英特尔真的需要好好地去看看他们的CPU了。在其看来,与其花力气写公关文倒不如承认他们的芯片存在缺陷。 很显然,Torvalds当谈及这些问题的时候完全不会忌讳什么。而英特尔的合作商们则在悄然采取修复行动的同时还特别提到了存在于AMD芯片和ARM构架的另一个漏洞--Spectre。确实,在科技行业中,批评向来都是比较温和的,但在Torvalds那儿却是行不通的: 或者英特尔说的是‘我们一直致力于并将一直向你们销售狗屁玩意儿,并且决定不会修复?’ 因为如果是这样的话,或许我们应当开始关注ARM64。
[半导体设计/制造]
linux-2.6.32在mini2440开发板上移植-移植I2C-EEPROM 驱动
1 在内核中配置I2C 驱动 Linux-2.6.32.2 对S2C2440 的I2C 接口提供了完善的驱动,因此我们只需在内核中配置一下即可使用。 在内核源代码目录执行:make menuconfig,进入内核配置主菜单,依次选择进入如下子菜单: Device Drivers --- * I2C support --- I2C Hardware Bus support --- 如图,我们看到这里已经选择好了“ * S3C2410 I2C Driver”,这里的S3C2410 也可以适用于S3C2440,因为它们的I2C 端口及寄存器定义都是完全相同的。 以上配置所对
[单片机]
<font color='red'>linux</font>-2.6.32在mini2440开发板上移植-移植I2C-EEPROM 驱动
基于FPGA的DS/CDMA解扩解调模块设计与实现
在CDMA通信系统中,用于基站信号转发的接收机是一个核心模块,一台接收机只是处理一路用户的解扩解调显然是不合理的,为了提高接收机的效率和降低成本,有必要设计一种多路CDMA信号通用解扩解调平台。而FPGA具有功能强大,开发工程投资小,周期短,可反复编程修改,保密性能好,开发工具智能化等优点,本项目决定采用FPGA作为设计平台;本文首先建立了CDMA信号的扩频调制与解扩解调系统模型,然后提出设计这样一个多路CDMA信号通用解扩解调平台。该平台将保证处理CDMA解扩解调的通用性,既可以将此平台用在CDMA信号蜂窝基站的建设上,也可以用在CDMA卫星地面的基站建设上。   图1 DS/CDMA解扩解调系统原理框图   1 DS
[单片机]
基于FPGA的DS/CDMA解扩解调模块设计与实现
s3c2410_gpio_cfgpin等内核导出函数
//这里面的函数都是内核导出函数/plat-s3c24XX/gpio.c中 #include linux/kernel.h #include linux/init.h #include linux/module.h #include linux/interrupt.h #include linux/ioport.h #include linux/io.h #include mach/hardware.h #include mach/gpio-fns.h #include asm/irq.h #include mach/regs-gpio.h //设置gpio的工作模式,是输入,输出还是其他的 //s3c2410
[单片机]
玩转mini2440开发板之【linux内核的编译和下载】
今天首先来玩一玩linux内核的编译和下载。 1、背景交代 开发环境:64位的Ubuntu 14.04; 编译工具:arm-linux-gcc 4.4.3; 下载工具:SuperViVi USB Transfer Utility; 调试工具:SecureCRT 7.2.6; 开发板材:友善之臂mini2440(64M版本); 内核版本:linux-2.6.32.2-20150709; 2、编译步骤 首先按照友善之臂官方手册(mini2440用户手册-20140103)的介绍,将linux 2.6.32.2的源码解压出来,我本人是解压到/opt/FriendlyARM/mini2440/linux-2.6.32.2-2015
[单片机]
玩转mini2440开发板之【<font color='red'>linux</font>内核的编译和下载】

推荐帖子

【颁奖礼】摸黑抢楼赢大礼!
示波器应该算我们身边最铁的哥们了,在实验室里,在工作台上,他们总是与我们形影不离。也许,你已经练就了一身只对示波器的独门秘籍......【颁奖礼】摸黑抢楼赢大礼!
soso 活动列表
华大单片机FLASH操作说明及注意事项
华大单片机根据型号不同,涵盖了16/32/64/128/256/512K字节(Byte)容量的FLASH存储器,每块FLASH按照Sector进行划分,每个Sector容量为512字节。本存储器支持对擦除(片/页擦除)、编程以及读取操作。此外,本模块还支持对FLASH存储器擦写的保护,以及控制寄存器的写保护。擦写时间FLASH存储器对擦除和编程操作的控制信号具有严格的时间要求,控制信号的时序不合格会造成擦除操作和编程操作失败或者数据写入深度不够。上电时默认装载了HC
火辣西米秀 国产芯片交流
【KW41Z】晒板子
终于收到板子了【KW41Z】晒板子
dvd1478 NXP MCU
光电转换技术新突破:用红外线与紫外线发电
日本的科学家研发出一种新的PV芯片技术,他们在传统的P型GaN薄膜上增添一层钴,并将之制成N型的材料(图右),而该芯片吸收层约为10x10mm,周围长方型的是电极。图左是无钴的P型GaN薄膜。此新技术不但能吸收可见光,包含红外线与紫外线都能转换为电能,将有望生产无多重接点的高性能光电产品。(图/Physorg)光电转换技术新突破:用红外线与紫外线发电
天天谈芯 嵌入式系统
电子类使用小程序收集
本帖最后由paulhyde于2014-9-1503:04编辑想用的时候参考一下啊电子类使用小程序收集本帖最后由paulhyde于2014-9-1503:04编辑都什么东西啊本帖最后由paulhyde于2014-9-1503:04编辑谢谢哟,学习了。本帖最后由paulhyde于2014-9-1503:04编辑都有些什么东西哦8.29本帖最后由paulhyde于2014-9-1503:05
非雪之悠 电子竞赛
EDN新开通“模拟学堂”,提供大量电子电路图下载和在线查看。欢迎访问!
http://www.ednchina.com/Analog.aspxEDN新开通“模拟学堂”,提供大量电子电路图下载和在线查看。欢迎访问!
babyjiejie 电源技术
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved