3. 中断控制器节点基础:标准节点定义与核心属性
中断控制器(Interrupt Controller)是嵌入式系统中管理硬件中断请求的核心单元。在设备树中,中断控制器节点通过一组标准属性来描述其能力、连接关系和中断编号格式。本节将详细解析这些属性的语义、用法和约束。
3.1 中断控制器节点的标准属性
一个完整的中断控制器节点通常包含以下三个核心属性,它们共同构成了中断资源描述的基础框架:
| 属性名 | 类型 | 必需性 | 描述 |
|---|---|---|---|
interrupt-controller |
空属性(boolean) | 必需 | 声明该节点是一个中断控制器,可接收并分发中断信号 |
#interrupt-cells |
u32 | 必需 | 指定中断描述符所需的单元数(即子节点中 interrupts 属性的长度) |
interrupt-parent |
phandle | 可选(但常见) | 指向该中断控制器的父中断控制器,用于构建中断级联层次 |
关键理解:
interrupt-controller 是一个布尔标志,不携带值;#interrupt-cells 决定了中断描述符的编码格式;interrupt-parent 用于连接多个中断控制器形成树状结构。
3.2 中断控制器节点结构示意图
下图展示了一个典型的中断控制器节点在设备树中的位置及其与子节点的关系:
3.3 核心属性详解
3.3.1 interrupt-controller 属性
该属性是一个空属性(无值),仅作为标志存在。当设备树解析器遇到此属性时,会将该节点注册为中断控制器,并允许其他节点通过 interrupt-parent 引用它。
实践要点: 一个设备树中可以存在多个中断控制器节点(如 GIC、GPIO 控制器、定时器),每个都必须声明
interrupt-controller 属性。根节点通常不声明此属性,除非 SoC 设计特殊。
3.3.2 #interrupt-cells 属性
该属性定义了一个中断描述符由多少个 32 位单元(cell)组成。不同的中断控制器使用不同的编码格式:
| #interrupt-cells 值 | 典型中断控制器 | 中断描述符格式 | 示例 |
|---|---|---|---|
| 1 | 简单 GPIO 控制器 | <中断号> | interrupts = <17>; |
| 2 | ARM GIC(旧版) | <中断类型 中断号> | interrupts = <0 33>; |
| 3 | ARM GIC(新版) | <中断类型 中断号 触发方式> | interrupts = <0 33 4>; |
| 4 | 特定 SoC 自定义 | <域 中断号 触发方式 优先级> | interrupts = <0 12 1 3>; |
常见错误: 子节点中
interrupts 属性的单元数必须严格等于父中断控制器的 #interrupt-cells 值。如果 GIC 声明 #interrupt-cells = <3>,则子节点必须提供 3 个单元,否则内核解析会失败。
3.3.3 interrupt-parent 属性
该属性是一个 phandle(指针句柄),指向该设备的中断控制器父节点。它定义了中断请求的路由目标:
- 显式声明: 在设备节点中直接使用
interrupt-parent = <&gic>;指定父中断控制器。 - 继承机制: 如果子节点未声明
interrupt-parent,则继承其父节点的interrupt-parent,逐级向上直到根节点。 - 根节点默认: 根节点可以设置
interrupt-parent作为整个系统的默认中断控制器。
3.4 中断级联与层次结构
在复杂 SoC 中,多个中断控制器可以级联形成层次结构。每个中断控制器既是父节点的中断控制器,又是子节点的中断父节点。下图展示了这种级联关系:
3.5 完整的中断控制器节点示例
以下是一个基于 ARM GIC-400 的完整中断控制器节点定义,展示了所有核心属性的实际用法:
// 顶层中断控制器(GIC)
gic: interrupt-controller@f0001000 {
compatible = "arm,gic-400";
reg = <0x0 0xf0001000 0x0 0x1000>,
<0x0 0xf0002000 0x0 0x2000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupts = <1 9 0xf04>; // 级联到父中断控制器(如果有)
};
// 子设备节点引用 GIC
uart0: serial@f0003000 {
compatible = "arm,pl011";
reg = <0x0 0xf0003000 0x0 0x1000>;
interrupt-parent = <&gic>;
interrupts = <0 33 4>; // 类型=0(SPI),中断号=33,触发方式=4(高电平)
};
// 另一个子设备
dma0: dma-controller@f0004000 {
compatible = "arm,pl330";
reg = <0x0 0xf0004000 0x0 0x1000>;
interrupt-parent = <&gic>;
interrupts = <0 56 4>, // 主中断
<0 57 4>; // 辅助中断
};
编码规则: 在
#interrupt-cells = <3> 的 GIC 中,第一个单元表示中断类型(0=SPI 共享外设中断,1=PPI 私有外设中断),第二个单元表示中断号,第三个单元表示触发方式和优先级标志。
3.6 属性使用注意事项
- 唯一性: 每个中断控制器节点必须具有唯一的
interrupt-controller声明,不能重复。 - 一致性: 同一中断控制器下的所有子节点必须使用相同的
#interrupt-cells格式。 - 级联深度: 中断控制器可以无限级联,但实际硬件设计通常不超过 3 层。
- 默认父节点: 如果根节点设置了
interrupt-parent,则所有未显式指定父节点的设备默认使用该中断控制器。 - 中断号范围: 中断号必须在中断控制器支持的范围内(如 GIC-400 支持 0-1019)。
调试建议: 当设备树中断绑定失败时,首先检查
interrupt-parent 的 phandle 是否正确,其次确认 interrupts 的单元数与 #interrupt-cells 匹配。使用 dtc -I dtb -O dts 反编译设备树可以快速验证这些属性。