3.7 DW_axi_dmac
3.7.1 设计特点
DW_axi_dmac是Synopsys公司设计的一款高性能、可配置的DMA(直接内存访问)控制器IP核,专为基于AMBA AXI总线的SoC系统打造。它旨在卸载CPU的数据搬运任务,通过硬件加速实现外设与内存之间的高效数据传输,显著提升系统吞吐量和实时性。
1. 架构与接口特性
- 总线接口:提供 AXI 主接口(用于高速数据读写)和 AXI/AXI-Lite/APB 从接口(用于 CPU 对控制/状态寄存器的配置与访问),支持 32/64 位数据宽度。
- 通道架构:支持多通道(最多可配置 8 个或 16 个独立通道),各通道可独立配置、并行工作,支持通道优先级管理。
- 硬件握手:提供硬件握手接口(DMA_REQ/DMA_ACK/DMA_FINISH),支持硬件/软件握手,提供细粒度(单事务)和粗粒度(块传输)的握手机制,满足不同外设的流控需求。
2. 传输模式与机制
-
传输类型:支持内存到内存(M2M)、内存到外设(M2P)、外设到内存(P2M)及外设到外设(P2P)传输,支持多种传输粒度(单事务、突发传输)。
-
多块传输(Multi-Block)
:支持三种多块传输机制,以适应不同的连续数据传输需求:
- 链表传输(Linked List):通过链表项(LLI)自动读取下一块传输参数,支持 scatter-gather(分散-聚集)传输,适合处理物理不连续的数据块。
- 自动重载(Auto-Reloading):在块传输完成后,自动将预设的初始值重新加载到通道寄存器,适合周期性、重复性的数据传输(如刷新缓冲区)。
- 连续地址传输(Contiguous Address):块传输完成后,自动将地址递加作为下一块的起始地址,适合处理物理连续的大数据块。
-
突发传输(Burst):支持可配置的突发长度(如 1、4、8、16、32、64、128 等),通过合并连续传输减少总线请求次数,提升传输效率。
3. 传输控制与配置
- 灵活的配置:支持可配置的传输宽度(8/16/32/64 位)和地址递增/递减模式,支持通道控制寄存器(CH_CTL)和配置寄存器(CH_CFG)的独立配置,支持影子寄存器机制,实现无缝的连续传输。
- 流控与仲裁:支持多种流控模式(DMA 控制器控制、外设控制),支持通道锁定与仲裁,保证高优先级通道的实时性。
4. 中断与状态管理
- 中断机制:提供全局中断和通道独立中断,支持块传输完成中断、错误中断等,支持中断屏蔽与清除,便于CPU进行传输状态监控和异常处理。
- 状态反馈:提供丰富的状态寄存器(如传输状态、中断状态),支持状态写回机制,便于软件进行传输结果确认和调试。
3.7.2 核心寄存器总览
dw_axi-dmac的寄存器主要分为两个大的部分,一部分为全局寄存器 ,另一部分为每个传输通道私有寄存器。
- Common registers
| 偏移量 | 寄存器名称 | 功能概述 |
|---|---|---|
| 0x000 | DMAC_ID | Component ID Register |
| 0x008 | DMAC_COMPVER | Component Version Register |
| 0x010 | DMAC_CFG | Global Configuration Register (配置寄存器) |
| 0x018 | DMAC_CHEN | Channel Enable Register (使能寄存器,一个bit使能一个通道) |
| 0x020 | DMAC_CHSUSPREG | Channel Suspend Register |
| 0x028 | DMAC_CHABORTREG | Channel Abort Register |
| 0x030 | DMAC_INTSTATUS | Combined Interrupt Status Register |
| 0x038 | DMAC_COMMON_INTCLEAR | Common Register Space Interrupt Clear Register |
| 0x040 | DMAC_COMMON_INTSTATUS_ENA | Common Register Space Interrupt Enable Register |
| 0x048 | DMAC_COMMON_INTSIGNAL_ENA | Common Register Space Interrupt Signal Enable Register |
| 0x050 | DMAC_COMMON_INTSTATUS | Common Register Space Interrupt Status Register |
| 0x058 | DMAC_RESET | Software Reset Register |
- DMA channel registers
| 偏移量 | 寄存器名称 | 功能描述 |
|---|---|---|
| 0x000 | CH_SAR | Channel x Source Address Register(数据源地址寄存器) |
| 0x008 | CH_DAR | Channel x Destination Address Register(目的地址寄存器) |
| 0x010 | CH_BLOCK_TS | Channel x Block Transfer Size Register (这个地址的值根据传输长度和数据宽度得出) |
| 0x018 | CH_CTL | Channel x Control Register (控制寄存器) |
| 0x020 | CH_CFG | Channel x Configuration Register (配置寄存器) |
| 0x028 | CH_LLP | Channel x Linked List Pointer Register (链表模式下使用该寄存器) |
| 0x030 | CH_STATUS | Channel x Status Register |
| 0x038 | CH_SWHSSRC | Channel x Software Handshake Source Register |
| 0x040 | CH_SWHSDST | Channel x Software Handshake Destination Register |
| 0x048 | CH_BLK_TFR_RESUMEREQ | Channel x Block Transfer Resume Request Register |
| 0x50 | CH_AXI_ID | Channel x AXI ID Register |
| 0x58 | CH_AXI_QOS | Channel x AXI QoS Register |
| 0x60 | CH_SSTAT | Channel x Source Status Register |
| 0x68 | CH_DSTAT | Channel x Destination Status Register |
| 0x70 | CH_SSTATAR | Channel x Source Status Fetch Register |
| 0x78 | CH_DSTATAR | Channel x Destination Status Fetch Register |
| 0x080 | CH_INTSTATUS_ENA | Channel x Interrupt Status Enable Register |
| 0x088 | CH_INTSTATUS | Channel x Interrupt Status Register(可以查询bit2判断传输是否完成) |
| 0x090 | CH_INTSIGNAL_ENA | Channel x Interrupt Signal Enable Register(需要使能才会有中断信号) |
| 0x098 | CH_INTCLEAR | Channel x Interrupt Status Clear Register(传输完成时清中断) |
3.7.3 核心寄存器详解
**CH_SAR和CH_DAR:**数据的源地址寄存器和目的寄存器,即数据从哪搬运到哪。
CH_BLOCK_TS:需要配置bit0-bit21,寄存器的值等于CHx_CTL.SRC_TR_WIDTH的数据总数,假设src的位宽是16,len为64字节,那么block_ts就等于32。
DMAC_CFG:DMA控制器初始化时,需要使能bit0和bit1
| bit | 字段名 | 功能描述 |
|---|---|---|
| 0 | DMAC_EN | 全局dma功能使能位 |
| 1 | INT_EN | 全局中断使能位 |
| 2-63 | RSVD_DMAC_CFGREG | 保留 |
**CH_CTL:**通道的控制寄存器主要配置以下几个字段,验证时可以配置不同的值,根据不同的值和传输的数据长度计算得出block_ts的值。
| bit | 字段名 | 功能描述 |
|---|---|---|
| 8-10 | SRC_TR_WIDTH | Source Transfer Width. |
| 11-13 | DST_TR_WIDTH | Destination Transfer Width |
| 14-17 | SRC_MSIZE | Source Burst Transaction Length. |
| 18-21 | DST_MSIZE | Destination Burst Transaction Length. |
CH_CFG:配置为单块传输时,bit0-bit3配置为0x00,配置为链表传输时,bit0-bit3配置为0xff,bit32-bit34配置传输类型,bit35-bit36配置为软件握手,即模拟dma搬运数据由软件写寄存器触发。
| bit | 字段名 | 功能描述 |
|---|---|---|
| 0-1 | SRC_MULTBLK_TYPE | 00: Contiguous 01:Reload 10: Shadow Register 11:11: Linked List |
| 2-3 | DST_MULTBLK_TYPE | 00: Contiguous 01:Reload 10: Shadow Register 11:11: Linked List |
| 32-34 | TT_FC | Transfer Type and Flow Control.(00是mem,01是m2d,03是d2m,04是d2d) |
| 35 | HS_SEL_SRC | Source Software or Hardware Handshaking Select. |
| 36 | HS_SEL_DST | Destination Software or Hardware Handshaking Select |
CH_INTSIGNAL_ENA: 该寄存器主要配置bit1,当一次dma传输完成时,生成一个中断信号。
CH_LLP:
当使用链表传输模式时,需要配置该寄存器,写入该寄存器的值为Link List的起始地址,地址的解析如下:

通常会用一个结构体进行表示:
struct axi_dma_llp {
u64 sar;
u64 dar;
u32 block_ts_lo;
u32 block_ts_hi;
u64 llp;
u32 ctl_lo;
u32 ctl_hi;
u32 sstat;
u32 dstat;
u32 status_lo;
u32 ststus_hi;
u32 reserved_lo;
u32 reserved_hi;
};
3.7.4 编程概要
-
单块传输
- 全局配置寄存器配置,使能dma和int项。
- 配置通道源地址寄存器和目的寄存器。
- 根据传输的数据长度和src_width计算block_n,并配置CH_BLOCK_TS寄存器。
- 通道配置寄存器配置,配置传输模式,软件握手,传输方向等。
- 通道控制寄存器配置,配置Burst Transaction Length和Transfer Width。
- 使能通道等中断信号。
- 使能通道的使能信号开始传输。
- 检测通道的中断状态寄存器,判断传输是否完成。
- 清中断,关闭通道使能位,并关闭全局寄存器的dma,int使能位。
- 数据对比判断是否传输成功。
-
链表传输
-
链表传输模式配置过程和单块传输模式类似,需要在配置传输模式时,配置为链表传输,以下是示例:
void AXI_DMA_TRAN_INIT_LLI(struct axi_dma_info axi, TEQ_UINT32 src_addr, TEQ_UINT32 dst_addr, TEQ_UINT32 length) { unsigned long axi_data; AXI_DMA_INIT(); axi_data = CHx_CONFIG(axi, TYPE_LLI); //lli模式下控制寄存器的配置 struct axi_dma_lli* head = (void *)LLI_ADDR; struct axi_dma_lli* tmp = head; TEQ_UINT32 num = 1; //这一步过后num等于2,链表里有2个元素 while (tmp->llp != (long)NULL) { tmp = (struct axi_dma_lli*)(TEQ_INT32)tmp->llp; num++; } tmp = head; //到这里tmp又指向head,即LLI_ADDR TEQ_UINT32 cnt; TEQ_UINT32 increment = length / num; //两个元素,一个搬一半? TEQ_UINT32 block_ts = cal_block_ts(axi.src_width, increment); //这个值要写到寄存器里 for (cnt = 0; cnt < num; cnt++) { tmp->sar = src_addr + increment * cnt; tmp->dar = dst_addr + increment * cnt; tmp->block_ts_lo = block_ts; tmp->ctl_lo = axi_data; if (tmp->llp == (long)NULL) tmp->ctl_hi = LAST_ITEM | VALID;//last & valid else tmp->ctl_hi = NOT_LAST_ITEM | VALID; tmp = (struct axi_dma_lli*)(TEQ_INT32)tmp->llp; } //Configure CHx_LLP(x0128) Starting Address Memory of LLI block write_mreg32(CHx_LLP(axi.channel), LLI_ADDR); }
-
参考:
1:DW_axi_dmac_databook.pdf
2:linux/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c