4. DMA控制器设备树绑定规范
设备树中DMA控制器的绑定规范是驱动开发者与硬件描述之间的契约。本章详细解析dma-controller节点、#dma-cells属性、dma-channel-mask以及dma-capabilities的核心定义与配置方法。
学习目标:掌握DMA控制器设备树节点的标准结构,理解各属性的语义与约束,能够独立编写或校验DMA控制器的设备树绑定。
4.1 dma-controller 节点结构
每个DMA控制器在设备树中必须声明为一个dma-controller节点,该节点是DMA Engine框架识别硬件控制器的入口。节点通常位于soc总线节点下,包含一组标准属性和控制器特定的属性。
以下是一个典型的DMA控制器节点示例:
dma: dma-controller@1c00000 {
compatible = "vendor,axi-dma-1.0";
reg = <0x01c00000 0x1000>;
interrupts = <0 12 4>;
#dma-cells = <3>;
dma-channel-mask = <0x3f>;
dma-capabilities = <0x0007>;
clocks = <&clk 5>;
resets = <&rst 5>;
dma-channels = <6>;
status = "okay";
};
关键字段说明:
compatible:驱动匹配字符串,必须与驱动中的of_device_id表一致。reg:DMA控制器的寄存器基地址和地址范围。interrupts:DMA控制器中断号,通常为1个或多个。#dma-cells:指定DMA请求端(consumer)节点中dma属性所需的参数个数。dma-channels:硬件支持的DMA通道总数(可选,但推荐显式声明)。
4.2 #dma-cells 属性详解
#dma-cells是DMA控制器节点中最重要的绑定属性之一,它定义了DMA请求端(consumer)节点中dmas属性所需的参数个数。该属性直接决定了DMA通道、请求线、优先级等信息的编码方式。
| #dma-cells 值 | 典型含义 | 使用场景 |
|---|---|---|
| 1 | 仅指定DMA通道号 | 简单DMA控制器,每个外设固定通道 |
| 2 | 通道号 + 请求线/外设ID | 多请求线DMA,如PL330、DMA-330 |
| 3 | 通道号 + 请求线 + 传输类型/优先级 | 复杂DMA控制器,支持多种传输模式 |
| 4+ | 扩展参数(如突发长度、地址宽度等) | 自定义或特殊DMA控制器 |
consumer节点中的dmas属性使用示例:
/* #dma-cells = <2> 的情况 */
uart0: serial@1f00000 {
compatible = "vendor,uart";
reg = <0x01f00000 0x1000>;
interrupts = <0 20 4>;
dmas = <&dma 0 2>, /* 通道0,请求线2(TX) */
<&dma 1 3>; /* 通道1,请求线3(RX) */
dma-names = "tx", "rx";
};
常见错误:
#dma-cells的值必须与驱动中of_dma_xlate_by_chan_id或自定义翻译函数的参数个数严格匹配。若consumer节点中dmas提供的参数个数少于#dma-cells,内核解析时会报错并返回NULL,导致DMA请求失败。
4.3 dma-channel-mask 属性
dma-channel-mask是一个位掩码属性,用于标识DMA控制器中哪些通道是物理可用的。该属性在硬件设计存在通道缺失或保留通道时尤为重要。
属性格式:
dma-channel-mask = <0x3f>; /* 位0~5有效,共6个通道 */
位掩码的每一位对应一个DMA通道:
- 位0 → 通道0
- 位1 → 通道1
- 位2 → 通道2
- ……
- 位N → 通道N
当某位为1时,表示该通道可用;为0时表示该通道不可用或保留。
| 掩码值 | 二进制 | 可用通道 | 说明 |
|---|---|---|---|
| 0x3F | 0011 1111 | 通道0~5 | 6个通道全部可用 |
| 0x0F | 0000 1111 | 通道0~3 | 仅低4个通道可用 |
| 0x55 | 0101 0101 | 通道0,2,4,6 | 仅偶数通道可用 |
| 0x00 | 0000 0000 | 无 | 所有通道禁用(异常情况) |
驱动处理逻辑:DMA Engine驱动在初始化时读取
dma-channel-mask,遍历所有位,仅对标记为1的通道进行注册和初始化。未标记的通道不会出现在dma_device的chan_list中,consumer无法请求到这些通道。
4.4 dma-capabilities 属性
dma-capabilities是一个位掩码属性,用于描述DMA控制器硬件支持的能力集。该属性帮助DMA Engine框架在运行时快速判断控制器是否支持特定传输类型或特性,避免无效的通道请求。
标准能力位定义:
| 位 | 宏定义 | 值 | 描述 |
|---|---|---|---|
| 0 | DMA_CAP_MEMCPY | 0x0001 | 支持内存到内存拷贝 |
| 1 | DMA_CAP_MEMSET | 0x0002 | 支持内存填充(memset) |
| 2 | DMA_CAP_INTERLEAVE | 0x0004 | 支持交错传输(scatter-gather) |
| 3 | DMA_CAP_SG | 0x0008 | 支持分散/聚集列表 |
| 4 | DMA_CAP_CYCLIC | 0x0010 | 支持循环传输(音频流常用) |
| 5 | DMA_CAP_PRIVATE | 0x0020 | 支持私有/专用通道 |
配置示例:
/* 支持MEMCPY + MEMSET + SG */
dma-capabilities = <0x000B>; /* 0x0001 | 0x0002 | 0x0008 */
/* 支持所有标准能力 */
dma-capabilities = <0x003F>; /* 位0~5全部置1 */
驱动最佳实践:在DMA Engine驱动的
probe函数中,读取dma-capabilities后,应将其与硬件实际能力进行交叉校验。如果设备树声明了某能力但硬件不支持,驱动应记录警告并清除该能力位,避免上层模块误用。
4.5 属性组合与校验流程
DMA控制器设备树绑定的完整校验流程如下:
- 节点识别:内核通过
compatible匹配驱动,调用of_match_node。 - 资源获取:解析
reg、interrupts、clocks等基础资源。 - 通道解析:读取
dma-channel-mask,确定可用通道位图。 - 能力解析:读取
dma-capabilities,填充dma_device的cap_mask。 - 翻译注册:根据
#dma-cells注册of_dma_xlate回调函数。 - 通道初始化:遍历可用通道位图,为每个通道分配
dma_chan结构并初始化。
4.6 常见问题与避坑指南
避坑1:#dma-cells 与 dmas 参数不匹配
若控制器声明
若控制器声明
#dma-cells = <3>,但consumer节点中dmas只提供2个参数,内核解析时会返回NULL。务必检查所有consumer节点的dmas属性参数个数是否一致。
避坑2:dma-channel-mask 与 dma-channels 冲突
dma-channel-mask中置1的位数必须小于等于dma-channels声明的总数。例如dma-channels = <4>但dma-channel-mask = <0x3F>(6个位为1),会导致驱动尝试初始化不存在的通道,引发访问越界。
调试技巧:在驱动中添加以下打印语句,可快速验证设备树属性是否正确解析:
dev_info(dev, "channel mask: 0x%x\n", chan_mask);
dev_info(dev, "capabilities: 0x%x\n", caps);
dev_info(dev, "#dma-cells: %d\n", cells);
通过dmesg日志即可确认设备树解析结果。
4.7 完整绑定示例
以下是一个完整的DMA控制器设备树绑定示例,包含所有核心属性:
/ {
soc {
dma0: dma-controller@10000000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x10000000 0x1000>;
interrupts = <0 25 4>;
#dma-cells = <2>;
dma-channel-mask = <0x0F>; /* 通道0~3可用 */
dma-capabilities = <0x000B>; /* MEMCPY | MEMSET | SG */
dma-channels = <4>;
clocks = <&clk 10>;
clock-names = "apb_pclk";
status = "okay";
};
uart1: serial@10100000 {
compatible = "arm,pl011";
reg = <0x10100000 0x1000>;
interrupts = <0 30 4>;
dmas = <&dma0 0 2>, /* 通道0,请求线2(TX) */
<&dma0 1 3>; /* 通道1,请求线3(RX) */
dma-names = "tx", "rx";
};
};
};
该示例中:
- DMA控制器使用PL330 IP核,兼容ARM PrimeCell标准。
- 仅通道0~3可用(掩码0x0F),支持内存拷贝、内存填充和分散/聚集传输。
- UART1使用通道0和通道1,分别对应TX和RX请求线。
本章小结:DMA控制器的设备树绑定规范是DMA Engine驱动开发的基石。
dma-controller节点定义了硬件资源,#dma-cells决定了consumer与controller之间的参数契约,dma-channel-mask和dma-capabilities则分别从通道可用性和能力集两个维度描述了控制器的特性。正确理解和配置这些属性,是确保DMA子系统稳定运行的前提。