4. UART DMA设备树配置:dmas与dma-names属性详解、DMA通道与UART端口绑定、中断号配置

在全志T113平台上,要使UART驱动工作在DMA模式,设备树(Device Tree)的配置是核心环节。错误的配置将导致DMA传输失败、数据错乱甚至系统崩溃。本节将深入解析dmas、dma-names属性的语法规则,阐明DMA通道与UART端口的绑定逻辑,并说明中断号的配置要点。

关键认知:设备树中的DMA配置本质上是将UART的硬件FIFO事件(RX满/TX空)映射到DMA控制器的请求线(Request Line)上。T113的DMA控制器支持8个独立通道,每个UART端口需要占用2个通道(RX + TX)。

4.1 dmas属性详解:DMA通道描述符

dmas属性是一个phandle数组,用于描述UART外设所连接的DMA控制器及通道参数。其标准格式如下:

dmas = <dma_controller_phandle dma_channel_id dma_request_id>,
       <dma_controller_phandle dma_channel_id dma_request_id>;

每个三元组代表一个DMA通道的描述:

字段 说明 T113典型值
dma_controller_phandle DMA控制器的设备节点引用 &dma 或 &dma0
dma_channel_id DMA控制器内部的物理通道编号(0~7) 0~7,由驱动分配或静态指定
dma_request_id 外设DMA请求线编号,由SoC设计决定 UART0_RX=14, UART0_TX=15
常见错误:将dma_request_id误写为通道编号。T113的DMA请求线编号是SoC硬件固定的,必须查阅芯片手册确认。例如UART1的RX请求线为16,TX为17,与UART0不同。

以UART0为例,正确的dmas配置如下:

&uart0 {
    pinctrl-names = "default";
    pinctrl-0 = <&uart0_pins>;
    status = "okay";

    dmas = <&dma 2 14>,   /* RX通道:使用DMA通道2,请求线14 */
           <&dma 3 15>;   /* TX通道:使用DMA通道3,请求线15 */
    dma-names = "rx", "tx";
};
配置要点:
  • RX通道和TX通道必须使用不同的DMA物理通道,避免资源冲突。
  • 请求线编号必须与UART端口匹配:UART0=14/15, UART1=16/17, UART2=18/19, UART3=20/21。
  • DMA通道编号(2和3)可以任意选择,只要不与系统中其他DMA用户冲突即可。
dmas属性结构解析 dmas 属性数组 第1个三元组 (RX) &dma 2 14 第2个三元组 (TX) &dma 3 15 DMA控制器phandle DMA通道ID DMA请求线ID 请求线ID由SoC硬件决定 UART0: RX=14, TX=15 UART1: RX=16, TX=17

4.2 dma-names属性详解:通道语义映射

dma-names属性是一个字符串列表,为dmas中的每个通道赋予语义名称。驱动代码通过名称来获取对应的DMA通道资源,而不是依赖数组索引。这种设计提高了代码的可读性和可维护性。

dma-names = "rx", "tx";

名称与dmas数组中的顺序一一对应:

dmas索引 dma-names值 语义 驱动获取方式
0 "rx" 接收DMA通道 dma_request_slave_channel(dev, "rx")
1 "tx" 发送DMA通道 dma_request_slave_channel(dev, "tx")
命名规范:全志T113的UART驱动强制要求使用"rx"和"tx"作为dma-names。如果使用其他名称(如"uart0_rx"),驱动将无法正确获取DMA通道,导致DMA模式初始化失败。

4.3 DMA通道与UART端口绑定机制

DMA通道与UART端口的绑定分为静态绑定和动态分配两种模式。T113的DMA控制器支持动态分配,但设备树配置通常采用静态指定以确保确定性。

绑定流程如下:

  1. 设备树解析阶段:内核解析dmas属性,获取DMA控制器phandle、通道ID和请求线ID。
  2. DMA引擎注册:DMA控制器驱动向内核注册DMA通道池。
  3. 通道请求:UART驱动调用dma_request_slave_channel(),根据dma-names请求通道。
  4. 请求线映射:DMA引擎根据请求线ID配置硬件路由,将UART的FIFO事件连接到指定的DMA通道。
  5. 通道确认:UART驱动获得dma_chan结构体指针,完成绑定。
DMA通道与UART端口绑定流程 设备树解析 dmas / dma-names DMA引擎注册 通道池初始化 通道请求 dma_request_slave_channel() 请求线映射 FIFO事件 → DMA通道 绑定完成 请求线ID决定硬件路由 UART0_RX(14) → DMA_CH2 UART0_TX(15) → DMA_CH3 硬件路由由DMA控制器完成

4.4 中断号配置

即使UART工作在DMA模式,中断配置仍然必不可少。DMA模式下的中断分为两类:

中断类型 作用 配置位置 是否必需
UART外设中断 处理错误、超时、DMA完成等事件 UART节点中的interrupts属性 必需
DMA控制器中断 DMA传输完成、错误通知 DMA控制器节点内部管理 自动管理

UART节点的中断配置示例:

&uart0 {
    interrupt-parent = <&gic>;       /* 中断控制器:GIC */
    interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
    /* GIC_SPI: 共享外设中断类型
       32: UART0的中断号(T113硬件分配)
       IRQ_TYPE_LEVEL_HIGH: 高电平触发 */
};
中断号速查表(全志T113 UART):
  • UART0: GIC_SPI 32
  • UART1: GIC_SPI 33
  • UART2: GIC_SPI 34
  • UART3: GIC_SPI 35

注意:中断号是SoC硬件设计决定的,不同芯片型号可能不同,务必以T113数据手册为准。

4.5 完整配置示例与验证

以下是一个完整的UART0 DMA模式设备树配置:

&uart0 {
    pinctrl-names = "default";
    pinctrl-0 = <&uart0_pins>;
    status = "okay";

    /* DMA配置 */
    dmas = <&dma 2 14>,   /* RX: DMA通道2, 请求线14 */
           <&dma 3 15>;   /* TX: DMA通道3, 请求线15 */
    dma-names = "rx", "tx";

    /* 中断配置 */
    interrupt-parent = <&gic>;
    interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;

    /* 可选:DMA缓冲区大小配置 */
    dma-rx-buffer-size = <4096>;
    dma-tx-buffer-size = <4096>;
};

配置完成后,可以通过以下方式验证DMA是否生效:

  1. 查看内核启动日志:搜索"uart0: DMA mode enabled"或类似信息。
  2. 检查DMA通道状态:cat /sys/kernel/debug/dmaengine/channels查看通道分配情况。
  3. 性能测试:使用dd或自定义程序进行大数据量收发,对比CPU占用率。
调试陷阱:如果配置后DMA不工作,首先检查dma_request_id是否正确。T113的DMA请求线编号与UART端口号不是线性关系,例如UART2的RX请求线是18而不是16。务必对照芯片手册逐位确认。
DMA配置验证流程 步骤1:日志检查 dmesg | grep uart 搜索"DMA mode enabled" 步骤2:通道状态 cat /sys/kernel/debug/ dmaengine/channels 步骤3:性能测试 大数据量收发 对比CPU占用率 验证要点 DMA通道是否分配成功?中断是否正常触发?CPU占用是否显著降低?

4.6 常见配置错误与排查

错误现象 可能原因 排查方法
DMA传输无响应 dma_request_id错误 核对芯片手册请求线编号
数据错位或丢失 DMA通道ID冲突 检查其他外设的DMA通道使用情况
中断风暴 中断触发类型配置错误 确认IRQ_TYPE_LEVEL_HIGH与硬件匹配
驱动初始化失败 dma-names拼写错误 检查"rx"/"tx"是否小写且无空格