本文共 6202 字,大约阅读时间需要 20 分钟。
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 {
unsigned char number;
unsigned char in_use;
unsigned char irq_claimed;
unsigned char irq_enabled;
unsigned char xfer_unit;
enum s3c2410_dma_state state;
enum s3c2410_dma_loadst load_state;
struct s3c2410_dma_client *client;
enum s3c2410_dmasrc source;
unsigned long dev_addr;
unsigned long load_timeout;
unsigned int flags;
struct s3c24xx_dma_map *map;
void __iomem *regs;
void __iomem *addr_reg;
unsigned int irq;
unsigned long dcon;
s3c2410_dma_cbfn_t callback_fn;
s3c2410_dma_opfn_t op_fn;
struct s3c2410_dma_stats *stats;
struct s3c2410_dma_stats stats_store;
struct s3c2410_dma_buf *curr;
struct s3c2410_dma_buf *next;
struct s3c2410_dma_buf *end;
struct sys_device dev;
};
struct s3c24xx_dma_order {
struct s3c24xx_dma_order_ch channels[DMACH_MAX];
};
struct s3c24xx_dma_order_ch {
unsigned int list[S3C2410_DMA_CHANNELS];
unsigned int 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;//使能中断
}