首先介绍s3c2410与DMA相关的寄存器。
s3c2410共有4通道的dma,每通道9个寄存器,共36个。
1、DISRCn该寄存器保存待传送数据的源地址。
2、DISRCCn源控制寄存器。位1表示数据源的总线类型,位0表示地址是否自动增减。
3、DIDSTn该寄存器保存待传送数据的目的地址。
4、DIDSTCn目的控制寄存器。位1表示目的地址的总线类型,位0表示地址是否自动增减。
5、DCONDMA控制寄存器。
6、DSTATnDMA状态寄存器。
7、DCSRCn当前源地址寄存器。
8、DCDSTn当前目的地址寄存器。
9、DMASKTRIGnDMA 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-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6....
linux-2.6.15.5--kgdb-2.4.rar 含有 linux-2.6.15.5-kgdb-2.4.tar.bz2 kgdb_docu_full-2.4.pdf kgdb_full_2.2.pdf kgdbquickstart-2.4.pdf
linux-2.6.22.6.tar.bz2
linux-2.6.35.3-102c9c0.tar.bz2 —— 内核源码包 1、将源码包复制到Ubuntu操作系统中,使用下面的命令解压: tar jxvf linux-2.6.35.3-102c9c0.tar.bz2 2、进入解压后的源码目录,执行build-kernel脚本: ...
hive-jdbc-uber-2.6.5.0-292.jar 驱动下载,hive-jdbc-uber-2.6.5.0-292.jar,hive-jdbc-uber-2.6.5.0-292.jar
hive客户端工具DBever连接时所使用的驱动,hive-jdbc-uber-2.6.5.0-292.jar,hive-jdbc-uber-2.6.5.0-292.jar,hive-jdbc-uber-2.6.5.0-292.jar
commons-lang-2.6.jar包commons-lang-2.6.jar包commons-lang-2.6.jar包commons-lang-2.6.jar包commons-lang-2.6.jar包加源码
Linux系统更新版本数据包,需要更新版本:linux-2.6.35.7-20121027
HDP-GPL-2.6.4.0-centos7-rpm.tar.gz
hive-jdbc-uber-2.6.5.0-292.jar驱动
官网最新版: TortoiseGit-2.6.0.0-64bit TortoiseGit-LanguagePack-2.6.0.0-64bit-zh_CN
Linux kernel-2.6.38.1-i686.cfg
linux 2.6.23.4
redis64-2.6.12.1.rar redis64-2.6.12.1.rar redis64-2.6.12.1.rar
linux-2.6.35.7-gec-v3.0-20130916.tar.bz2
commons-fileupload-1.3.3.jar和commons-io-2.6.jar最新版本
linux-2.6.30.5.tar.bz2 linux2.6.30.5版本内核
utf8-kernel-2.6.22.5-core-1.patch
该资源是关于教高级版的2.6.的内核源代码,在升级的过程过程中需要。
JAVAcommons-fileupload-1.4.jar和commons-io-2.6.jar