4. 设备树中的中断与GPIO控制器
在嵌入式Linux网络驱动移植中,中断控制器(Interrupt Controller)与GPIO控制器(GPIO Controller)是设备树绑定的核心组成部分。网络接口卡(NIC)通常通过硬件中断线向CPU报告数据包到达、链路状态变化等事件,而GPIO则用于控制PHY复位、电源管理或LED指示。本章深入解析中断映射与GPIO引用的设备树描述机制。
4.1 中断控制器(interrupt-controller)
中断控制器是负责收集、优先级排序和分发硬件中断信号的IP核。在设备树中,中断控制器节点通过 interrupt-controller 布尔属性标识自身能力,并通过 #interrupt-cells 指定中断描述符所需的单元数。
| 属性 | 类型 | 描述 |
|---|---|---|
interrupt-controller |
空属性 | 声明该节点为中断控制器 |
#interrupt-cells |
u32 | 指定中断描述符的单元数(通常为1、2或3) |
interrupt-parent |
phandle | 指向父级中断控制器(用于级联场景) |
interrupts |
u32数组 | 描述该节点自身使用的中断线 |
以下是一个典型ARM GIC(Generic Interrupt Controller)的设备树节点示例:
gic: interrupt-controller@f1001000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xf1001000 0x1000>,
<0xf1000100 0x100>;
};
其中 #interrupt-cells = <3> 表示每个中断描述符由3个单元组成:中断类型(0=SPI,1=PPI)、中断号、触发标志(如上升沿、电平高)。
interrupts = <0 42 4>; 表示SPI中断号42,高电平触发。
4.2 中断映射(interrupt-map)
中断映射用于处理中断控制器级联或PCIe等总线桥接场景。当设备连接到中间总线(如PCIe Root Complex)时,需要将总线侧的中断请求映射到父级中断控制器的具体中断线。interrupt-map 属性定义了这种转换规则。
| 属性 | 类型 | 说明 |
|---|---|---|
interrupt-map |
u32数组 | 中断映射表,每行包含:子地址、子中断、父phandle、父中断描述符 |
interrupt-map-mask |
u32数组 | 掩码,用于匹配子地址和子中断 |
#interrupt-cells |
u32 | 子侧中断描述符单元数 |
PCIe中断映射典型示例:
pcie: pcie@f0000000 {
compatible = "pci-host-ecam-generic";
reg = <0xf0000000 0x10000000>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
0x0000 0 0 1 &gic 0 0 0 42 4
0x0000 0 0 2 &gic 0 0 0 43 4
0x0000 0 0 3 &gic 0 0 0 44 4
0x0000 0 0 4 &gic 0 0 0 45 4
>;
};
上述映射将PCIe设备的中断请求INTA#~INTD#分别映射到GIC的中断42~45(SPI类型,高电平触发)。
interrupt-controller 的节点,否则内核解析时会报“no irq domain found”错误。同时,父侧 #interrupt-cells 必须与映射表中父中断描述符的单元数一致。
4.3 GPIO控制器(gpio-controller)
GPIO控制器节点通过 gpio-controller 属性声明自身为GPIO控制器,并通过 #gpio-cells 指定GPIO描述符的单元数。网络驱动中常用GPIO控制PHY复位、电源使能或中断线复用。
| 属性 | 类型 | 描述 |
|---|---|---|
gpio-controller |
空属性 | 声明该节点为GPIO控制器 |
#gpio-cells |
u32 | 指定GPIO描述符单元数(通常为2:GPIO号 + 标志) |
gpio-ranges |
u32数组 | 将GPIO控制器映射到pinctrl子系统 |
典型GPIO控制器节点:
gpio0: gpio@f1002000 {
compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio";
reg = <0xf1002000 0x4000>;
interrupts = <0 68 4>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
其中 #gpio-cells = <2> 表示GPIO引用由两个单元组成:GPIO索引号(从0开始)和标志位(如GPIO_ACTIVE_HIGH=0,GPIO_ACTIVE_LOW=1)。
4.4 GPIO引用(gpios属性)
设备节点通过 gpios 或 *-gpios 属性引用GPIO控制器中的具体引脚。引用格式为:<phandle gpio-specifier>,其中phandle指向GPIO控制器节点,gpio-specifier根据 #gpio-cells 定义。
网络驱动中GPIO引用的典型场景:
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fec1>;
phy-mode = "rgmii";
phy-reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
phy-reset-duration = <10>;
status = "okay";
};
上述代码中 phy-reset-gpios 引用gpio1控制器的第15号引脚,低电平有效,用于PHY芯片硬件复位。
devm_gpiod_get_optional() 和 gpiod_set_value() 等API操作GPIO。设备树中的GPIO标志(如GPIO_ACTIVE_LOW)会被内核自动处理,驱动层无需手动反转电平。
4.5 中断与GPIO的协同工作
在网络驱动中,中断控制器和GPIO控制器经常协同工作。例如,PHY芯片的中断输出引脚可能连接到SoC的GPIO,此时该GPIO需要配置为中断输入模式。
设备树描述示例:
&fec1 {
pinctrl-0 = <&pinctrl_fec1>;
phy-mode = "rgmii";
phy-handle = <&phy0>;
status = "okay";
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
reg = <0>;
interrupts-extended = <&gpio1 16 IRQ_TYPE_EDGE_FALLING>;
};
};
这里 interrupts-extended 属性直接指定中断控制器为gpio1,中断号为16,下降沿触发。内核GPIO子系统会自动将gpio1_16配置为中断输入。
| 场景 | 中断控制器 | GPIO控制器 | 设备树属性 |
|---|---|---|---|
| MAC直接中断 | GIC | — | interrupts = <0 42 4>; |
| PHY中断通过GPIO | GPIO控制器 | gpio1 | interrupts-extended = <&gpio1 16 2>; |
| PHY复位控制 | — | gpio1 | phy-reset-gpios = <&gpio1 15 1>; |
| LED状态指示 | — | gpio2 | led-gpios = <&gpio2 5 0>; |
interrupts-extended 属性时,不能再同时使用 interrupt-parent 和 interrupts 属性,否则内核解析会冲突。此外,GPIO作为中断控制器使用时,必须确保该GPIO节点同时声明了 interrupt-controller 和 #interrupt-cells。
4.6 实践检查清单
在编写或移植网络驱动设备树时,请逐项确认以下要点:
- 中断控制器声明:确认SoC的中断控制器节点包含
interrupt-controller和#interrupt-cells。 - 中断父级指定:MAC节点通过
interrupt-parent或interrupts-extended正确指向中断控制器。 - 中断号与触发类型:核对芯片手册中的中断号,触发类型与硬件设计一致(电平/边沿)。
- GPIO控制器声明:确认GPIO节点包含
gpio-controller和#gpio-cells。 - GPIO引用格式:检查
phy-reset-gpios等属性的phandle和specifier是否正确。 - 中断映射一致性:对于PCIe等总线设备,验证
interrupt-map的掩码和映射表项与硬件拓扑匹配。 - 引脚复用冲突:确保GPIO引脚未被pinctrl子系统配置为其他功能。
cat /proc/interrupts 查看中断注册情况;使用 lsgpio 或 cat /sys/kernel/debug/gpio 检查GPIO状态;使用 dtc -I dtb -O dts 反编译设备树二进制文件验证绑定正确性。