本章主要探讨设备树的基本语法和使用技巧
子节点子节点是根节点的子项,用于描述具体的硬件设备或设备集合。
[label:] node-name@[unit-address] {
[properties definitions]
[child nodes]
};
REG属性表示子节点reg 属性用几个32 位的数表示地址,#size-cells 表示子节点reg 属性
用几个32 位的数表示地址长度
/ {
#address-cells = <0x1>; //在根节点下使用1 个u32 来代表address。
#size-cells = <0x0>; //在根节点下使用0 个u32 来代表size。
node1 {
reg = <0x32>; //表示地址是0x32。
};
}
model 属性model 是可选属性,用于描述设备的名称或型号,其值为字符串,便于识别和区分设备,
my_device {
compatible = "vendor,device";
model = "My Device XYZ";
// 其他属性和子节点的定义
};
status 属性status 属性用于描述设备或节点的状态,属性值是字符串。属性值有以下几种:okay 表示
设备或节点是可用状态;disabled 表示设备或节点是不可用状态;reserved 表示设备或节点已
被保留,暂时不可用;fail 表示设备或节点是不可用状态并且检测到了错误。
my_device {
compatible = "vendor,device";
status = "okay";
// 其他属性和子节点的定义
};
compatible 属性设备树中的设备节点使用compatible 属性的值与driver 进行匹配,如使用平台总线就要与
平台总线driver 部分中的platform_driver.driver.of_match_table 成员的值进行匹配,如果匹配成
功,即字符串值相等,则会执行平台总线driver 部分的probe()函数
/{
topeet{
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
myLed{
compatible = "my devicetree";
};
};
};
//平台总线模型的driver 部分
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
//匹配成功后执行probe 函数
static int my_platform_probe(struct platform_device *pdev)
{
printk(KERN_INFO "my_platform_probe: Probing platform device\n");
return 0;
}
const struct of_device_id of_match_table_id[] = {
{.compatible="my devicetree"},
};
aliases 节点aliases 是设备树根节点下的特殊节点,用于为设备节点定义别名,方便引用和管
aliases {
mmc0 = &sdmmc0;
mmc1 = &sdmmc1;
mmc2 = &sdhci;
serial0 = “/simple@fe000000/seria1@11c500”;
};
chosen 节点节点要位于设备树根节点下,它用于传递系统引导和配置相关信息。其中bootargs
属性用于存储引导内核时传递的命令行参数
chosen {
bootargs = “root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200”;
};
修改/追加节点内容语法格式为:&节点名,用于引用设备树中已有的节点
pinctrl: pinctrl {
compatible = "rockchip,rk3568-pinctrl";
status = "disabled";
}
&pinctrl {
status = "okay";//把pinctrl 节点中的属性值修改为okay
uart0 {//追加uart0 节点
/omit-if-no-ref/
uart0_xfer: uart0-xfer {
rockchip,pins =<0 RK_PC0 3 &pcfg_pull_up>,
<0 RK_PC1 3 &pcfg_pull_up>;
};
};
相关特定属性节点分析
中断:
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;//性用于描述设备所使用的中断号及触发方式,分别表示中断控制器类型、中断号和中断触发类型。其中中断控制器的常见类型包括GIC (Generic Interrupt Controller)、IRQ (Basic Interrupt Handling)等,触发类型:#define IRQ_TYPE_NONE 0 // 无中断触发类型
{
#define IRQ_TYPE_EDGE_RISING 1 // 上升沿触发
#define IRQ_TYPE_EDGE_FALLING 2 // 下降沿触发
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)// 双边沿触发
#define IRQ_TYPE_LEVEL_HIGH 4 // 高电平触发
#define IRQ_TYPE_LEVEL_LOW 8 // 低电平触发
}
clocks = <&pmucru PCLK_GPI00>, <&pmucru DBCLK_GPI00>;
gpio-controller;
#gpio-cells = <2>;//表示中断控制器下的设备描述一个中断所需的单元数。例如,GIC 控制器使用#interrupt-cells = <2>表示使用这个中断控制器的设备中的interrupts
属性需2 个参数。
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;//表明这个节点也是一个中断控制器节点
#interrupt-cells = <2>;
};
ft5x06: ft5x06@38 {
status = "disabled";
compatible = "edt,edt-ft5306";
reg = <0x38>;
touch-gpio = <&gpio0 RK_PB5 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio0>;//指明中断父节点是谁
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;//父节点要求这个中断需要两个参数进行描述
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <1280>;
touch_type = <1>;
};
这里补充两个小知识点:1.一个节点可以提示描述两个功能,2.设备树在多层包含和引用的情况下以那个文件为准。
一、GPIO 节点同时作为中断控制器和 GPIO 控制器
可以的,在设备树中这是常见设计。
原因
GPIO 引脚既可以作为普通输出/输入使用,也可以触发中断。例如:
按键按下 → GPIO 引脚电平变化 → 触发中断
触摸屏触摸 → GPIO 中断通知 CPU
你的文件中的体现
gpio0: gpio@fdd60000 {
gpio-controller; // ✅ 是 GPIO 控制器
#gpio-cells = <2>; // 每个 GPIO 引用需要 2 个 cell
interrupt-controller; // ✅ 也是中断控制器
#interrupt-cells = <2>; // 每个中断引用需要 2 个 cell
};
这表示 gpio0 节点同时承担两种角色,这是完全正确的设计。
二、interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW> 详解
2.1 完整参数结构
interrupt-parent = <&gpio0>; // 中断父控制器
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>; // 中断定义
interrupts 是一个数组,这里有 2 个 cell(#interrupt-cells = <2>)。
2.2 两个参数的含义
参数 含义 示例值
第1个 cell 中断号 (interrupt specifier) GPIO 引脚编号
第2个 cell 触发类型 (interrupt type) 电平/边沿触发
< 第1个cell 第2个cell >
<RK_PB5 IRQ_TYPE_LEVEL_LOW>
2.3 第一参数 RK_PB5 的含义
RK_PB5 是 GPIO 引脚标识符,表示:
RK_PB5
├── RK = Rockchip 芯片前缀
├── P = Port (端口/GPIO组) A=0, B=1, C=2, D=3
└── B5 = Pin 5 (第5号引脚,在P组中)
换算: P组第5脚 → GPIO Bank 1, Pin 5
命名规则:
RK_XXn
├── XX = 端口名 (PA, PB, PC, PD, PE, PF...)
└── n = 引脚号 (0-31)
标识 GPIO Bank Pin 序号 GPIO 编号
RK_PA0 0 0 GPIO0_A0
RK_PB5 1 5 GPIO1_B5
RK_PC2 2 2 GPIO2_C2
RK_PD15 3 15 GPIO3_D15
2.4 第二参数触发类型
IRQ_TYPE_NONE = 0x00000000 // 无触发
IRQ_TYPE_EDGE_RISING = 0x00000001 // 上升沿触发
IRQ_TYPE_EDGE_FALLING = 0x00000002 // 下降沿触发
IRQ_TYPE_EDGE_BOTH = 0x00000003 // 双边沿触发
IRQ_TYPE_LEVEL_HIGH = 0x00000004 // 高电平触发
IRQ_TYPE_LEVEL_LOW = 0x00000008 // 低电平触发 ← 你用的是这个
2.5 如何知道第一参数填什么
步骤1:确定使用的 GPIO 引脚
根据硬件原理图确定 GPIO 引脚,例如:
触摸芯片 IRQ ----→ GPIO1_B5 (RK_PB5)
触摸芯片 RST ----→ GPIO1_B6 (RK_PB6)
步骤2:查找 GPIO 编号
// pinctrl 中定义引脚复用
touch: touch-pins {
rockchip,pins = <
RK_PB5 RK_FUNC_GPIO &pcfg_pull_none // 作为 GPIO 使用
RK_PB6 RK_FUNC_GPIO &pcfg_pull_none
>;
};
步骤3:填写到 interrupts
touch@38 {
interrupt-parent = <&gpio1>; // GPIO1 控制器
interrupts = <RK_PB5 IRQ_TYPE_EDGE_RISING>; // PB5 上升沿触发
};
2.6 实际中断流程图
应用程序
↑
│ 中断信号
│
触摸芯片 IRQ 引脚
│
↓
┌──────────────────────────────────────┐
│ gpio0 控制器 (GPIO1) │
│ │
│ #interrupt-cells = <2> │
│ interrupt-controller; │
│ │
│ 接收: <RK_PB5 IRQ_TYPE_LEVEL_LOW> │
│ 识别: Bank 1, Pin 5 的中断 │
└──────────────────────────────────────┘
│ (转换为 GIC 中断号)
↓
┌──────────────────────────────────────┐
│ GIC (通用中断控制器) │
│ │
│ 分发中断到 CPU │
└──────────────────────────────────────┘
│
↓
CPU (Cortex-A)
三、设备树多层引用与覆盖规则(详细版)
3.1 include 加载顺序
dts/dtsi 文件通过 #include 包含,后加载的覆盖先加载的。
示例:Rockchip 典型加载顺序
rk3399.dts
├── #include "rk3399.dtsi" ← 第1层:SoC 基础定义
│ ├── #include "skeleton.dtsi"
│ ├── #include "dt-bindingings/xxx.dtsi"
│ └── 定义所有外设的默认状态
│
├── #include "rk3399-disvr.dtsi" ← 第2层:中间层
│ └── 可能覆盖部分外设
│
└── #include "rk3399-evb.dtsi" ← 第3层:板级(最后加载,生效)
└── 板级特定配置,覆盖前面的
3.2 覆盖规则详解
规则1:同路径节点 → 合并属性,冲突以后者为准
文件1: imx6ull.dtsi
/ {
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart";
reg = <0x02020000 0x4000>;
status = "okay"; // ← 属性A
pinctrl-names = "default";
};
};
文件2: board.dtsi
/ {
&uart1 {
status = "disabled"; // ← 覆盖!冲突,以后者为准
pinctrl-names = "sleep"; // ← 覆盖!
};
};
最终结果:
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart";
reg = <0x02020000 0x4000>; // ← 保留(无冲突)
status = "disabled"; // ← 被覆盖为 disabled
pinctrl-names = "sleep"; // ← 被覆盖为 sleep
};
规则2:同路径全新属性 → 追加
文件1: imx6ull.dtsi
/ {
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart";
reg = <0x02020000 0x4000>;
};
};
文件2: board.dtsi
/ {
&uart1 {
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>; // 全新属性,追加
pinctrl-0 = <&pinctrl_uart1>; // 全新属性,追加
};
};
最终结果:
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart";
reg = <0x02020000 0x4000>;
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>; // ← 新增
pinctrl-0 = <&pinctrl_uart1>; // ← 新增
};
规则3:同路径同属性数组 → 完全覆盖
文件1
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
文件2
interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>, // 覆盖!
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; // 新的
最终: 整个数组被替换为新的 2 个中断。
3.3 完整示例:多层覆盖
第1层: imx6ull.dtsi (SoC层)
/ {
compatible = "fsl,imx6ull";
#address-cells = <1>;
#size-cells = <1>;
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart";
reg = <0x02020000 0x4000>;
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
status = "okay"; // 默认开启
};
i2c1: i2c@021a0000 {
compatible = "fsl,imx6ul-i2c";
reg = <0x021a0000 0x4000>;
status = "okay";
};
};
第2层: imx6ull-alientek-emmc.dtsi (板级层)
/ {
// 覆盖 uart1 的状态
&uart1 {
status = "okay"; // 显式确认开启
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
};
// 覆盖 i2c1 的状态
&i2c1 {
status = "okay"; // 确认开启
clock-frequency = <100000>; // 100KHz I2C 速度
};
};
第3层: imx6ull-alientek-emmc.dts (机器层)
/ {
model = "ALIENTEK i.MX6ULL EMMC Board";
compatible = "alientek,imx6ull-alientek-emmc", "fsl,imx6ull";
// 调试时临时关闭 uart1
&uart1 {
status = "disabled"; // 覆盖!最终关闭
};
};
最终结果:
uart1: status = "disabled" ← 由 imx6ull-alientek-emmc.dts 决定
i2c1: status = "okay" ← 由 imx6ull-alientek-emmc.dtsi 决定
model: "ALIENTEK..." ← 由 imx6ull-alientek-emmc.dts 决定
3.4 优先级总结
include 加载顺序(从第1个到最后一个)
↑
│
1. skeleton.dtsi (最底层) ← 基础骨架
2. imx6ull.dtsi (SoC层) ← 外设默认定义
3. board.dtsi (板级层) ← 板级配置
4. board-custom.dtsi (自定义) ← 用户定制
5. board.dts (机器层) ← 最终生效
│
└──→ 最后的文件具有最终决定权
3.5 如何查看最终生效的配置
# 1. 编译 DTB
cd /home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull-alientek-emmc.dtb -j16
# 2. 反编译查看最终结果
./scripts/dtc/dtc -I dtb -O dts \
arch/arm/boot/dts/imx6ull-alientek-emmc.dtb > /tmp/final.dts
# 3. 查看特定节点的最终状态
grep -A 30 "uart1:" /tmp/final.dts
3.6 调试技巧
技巧1:在某文件中加一个特殊标记,方便追踪
// 在你的 board.dtsi 中加注释
&uart1 {
// 2024-01-01: 覆盖为 115200
status = "okay";
};
技巧2:用 ! 安全覆盖
dtsi 中的节点可以被完全替换:
// 完全替换(不安全)
uart1: serial@02020000 {
...
};
// 安全追加(推荐)
&uart1 {
...
};
技巧3:检查是否有多个定义冲突
# 在 .dts/.dtsi 文件中搜索同名节点
grep -r "uart1:" arch/arm/boot/dts/*.dtsi
好问题!让我逐一详细解答。
1. GPIO 节点的双重身份
GPIO 控制器 + 中断控制器的实现原理
在设备树中,同一个硬件节点可以同时声明两种功能:
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
// ① GPIO 控制器功能
gpio-controller;
#gpio-cells = <2>; // gpio 使用 2 个 cell
// ② 中断控制器功能
interrupt-controller;
#interrupt-cells = <2>; // 中断使用 2 个 cell
};
硬件层面的原理:
GPIO 控制器内部有中断状态寄存器和中断屏蔽寄存器
当 GPIO 引脚配置为输入模式时,引脚电平变化可以触发外设中断
内核为同一个 GPIO 控制器实例注册两个子系统:
gpio_chip (用于 GPIO 操作)
irq_chip (用于中断处理)
你当前文件中的问题
gpio0: gpio@fdd60000 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller; // ✓ 声明自己是中断控制器
#interrupt-cells = <2>; // 中断需要 2 个 cell
};
你的配置是正确的,可以同时作为 GPIO 和中断控制器使用。
2. interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>; 参数详解
参数结构
interrupts = <第一参数 第二参数 第三参数>;
你当前的配置:
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;
你的配置只有 2 个参数,但 #interrupt-cells = <2>
这意味着每个中断需要 2 个 cell:
参数 含义 说明
第 1 个 cell 中断号 / GPIO 引脚 哪个引脚触发中断
第 2 个 cell 中断触发类型 上升沿/下降沿/电平等
第一个参数(RK_PB5)的含义
RK_PB5 是一个宏,代表 GPIO 引脚编号
├─ RK_ = Rockchip 前缀
├─ P = Port (端口号, A~H)
├─ B = Bank (组号)
└─ 5 = 引脚号 (0~31)
标准格式:
格式 示例 含义
RK_PXnn RK_PB5 Port B, Pin 5
<&gpioX port pin> <&gpio0 1 5> gpio0, Port B, Pin 5
数字直接表示 <33> 直接是中断号 (GIC 中断号)
如何确定第一个参数
方法1:从原理图/芯片手册查找
例如:
RK_PB5 = GPIO0_B5 = (Bank B = 1) * 32 + Pin 5 = 37
RK_PC3 = GPIO0_C3 = (Bank C = 2) * 32 + Pin 3 = 67
方法2:查看芯片 dtsi 文件
在 rk3399.dtsi 或 imx6ull.dtsi 中查看宏定义:
// 常见的 GPIO 宏定义格式
#define RK_PA0 0
#define RK_PA1 1
#define RK_PA2 2
// ...
#define RK_PB0 32
#define RK_PB1 33
// ...
#define RK_PB5 37 // 1*32 + 5 = 37
方法3:参考其他已配置的 dts 文件
你的配置修正
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;
// 应该改为:
interrupts = <37 IRQ_TYPE_LEVEL_LOW>; // RK_PB5 = 1*32 + 5 = 37
// 或者使用 GPIO phandle:
interrupts = <&gpio0 1 5 IRQ_TYPE_LEVEL_LOW>; // &gpio0, Port B, Pin 5
⚠️ 注意:你的 #interrupt-cells = <2> 表示需要 2 个 cell(中断号 + 触发类型)。但如果中断控制器要求第一个参数是 GPIO 的 (port, pin) 对,那可能需要 3 个 cell。具体要看芯片手册和驱动代码。
触发类型宏说明
宏 含义
IRQ_TYPE_NONE 无触发
IRQ_TYPE_EDGE_RISING 上升沿触发
IRQ_TYPE_EDGE_FALLING 下降沿触发
IRQ_TYPE_EDGE_BOTH 双边沿触发
IRQ_TYPE_LEVEL_HIGH 高电平触发
IRQ_TYPE_LEVEL_LOW 低电平触发
3. 多层节点引用与状态决定机制(详细整理)
3.1 节点引用的三种方式
方式1:完整节点定义
/dts-v1/;
/ {
nodeA { // 完整定义一个节点
prop = "value";
};
};
方式2:节点引用 (&label)
/dts-v1/;
/ {
nodeA {
status = "disabled"; // 原始值
};
};
&nodeA {
status = "okay"; // 覆盖值
};
方式3:子节点追加
/dts-v1/;
/ {
parent {
child {
prop1 = "a";
};
};
};
&parent {
child {
prop2 = "b"; // 追加 prop2
prop1 = "c"; // 覆盖 prop1
};
};
3.2 完整的多层引用示例
文件结构
file1.dtsi (最早加载,基础定义)
│
▼
file2.dtsi (中间层,板级定制)
│
▼
file3.dts (最后加载,最终生效)
file1.dtsi (基础层)
/dts-v1/;
/ {
compatible = "rockchip,rk3399";
i2c1: i2c@ff110000 {
compatible = "rockchip,rk3399-i2c";
reg = <0xff110000 0x1000>;
clocks = <&cru CLK_I2C1>;
status = "okay"; // ← 原始状态
pinctrl-names = "default";
};
&i2c1 {
pinctrl-0 = <&i2c1_xfer>; // 追加引脚配置
};
};
file2.dtsi (板级层)
/dts-v1/;
/ {
// 引用并覆盖
&i2c1 {
status = "disabled"; // ← 覆盖为 disabled
clock-names = "i2c";
};
// 添加新子节点
&i2c1 {
/* file2 追加的子节点 */
};
};
file3.dts (最终层)
/dts-v1/;
#include "file1.dtsi"
#include "file2.dtsi"
/ {
&i2c1 {
status = "okay"; // ← 覆盖为 okay,最终生效
pinctrl-0 = <&i2c1_xfer &i2c1_pull>; // 合并引脚配置
};
};
3.3 include 顺序与覆盖规则
dts 文件 include 顺序:
// imx6ull-alientek-emmc.dts
/dts-v1/;
#include "imx6ull.dtsi" // ① 第1个加载
#include "imx6ull-alientek-emmc.dtsi" // ② 第2个加载 (覆盖)
dtc 编译器的处理逻辑:
dts 文件按行顺序处理,后出现的定义覆盖先出现的
加载顺序:
↓
┌─────────────────────────┐
│ imx6ull.dtsi │ 最早加载,设置默认值
│ ├── i2c1 status=okay │
│ └── pinctrl-0=xxx │
└──────────┬────────────────┘
↓ 覆盖
┌─────────────────────────┐
│ imx6ull-alientek-emmc │ 后加载,板级定制
│ ├── i2c1 status=disabled│ → 覆盖
│ └── pinctrl-1=yyy │ → 追加
└──────────┬────────────────┘
↓ 覆盖
┌─────────────────────────┐
│ 最终 .dtb 结果 │
│ ├── i2c1 status=disabled│
│ ├── pinctrl-0=xxx │ (来自 dtsi1)
│ └── pinctrl-1=yyy │ (来自 dtsi2)
└─────────────────────────┘
3.4 属性覆盖规则表
情况 处理方式 示例
同节点同名属性 后者覆盖前者 status = "okay" → status = "disabled"
同节点不同属性 合并 reg 保留 + interrupts 追加
子节点引用 合并子节点属性 子节点属性冲突时后者覆盖
同名子节点 合并到同一子节点 子节点内容被合并
全新节点/属性 追加 新内容被添加到结果
3.5 调试方法
# 查看最终 DTB 的内容,确认哪个文件生效
cd /home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
# 1. 反编译 DTB 为 DTS
./scripts/dtc/dtc -I dtb -O dts \
arch/arm/boot/dts/imx6ull-alientek-emmc.dtb > /tmp/final.dts
# 2. 查看特定节点
grep -A 20 "i2c1" /tmp/final.dts
# 3. 或者用 dtx_diff 查看差异
# (需要在不同阶段反编译然后对比)
# 4. 查看 include 了哪些文件
head -20 arch/arm/boot/dts/imx6ull-alientek-emmc.dts
3.6 常见错误
/* 错误1:引用不存在的节点 */
&nonexistent { // ← 节点不存在会报错
status = "okay";
};
/* 错误2:状态拼写错误 */
status = "ok"; // ← 不是 "okay",不会生效
status = "enable"; // ← 不是 "okay",不会生效
/* 正确值 */
status = "okay"; // 启用
status = "disabled"; // 禁用
status = "reserved"; // 保留
总结
问题 答案
GPIO 可否同时是中断控制器? 可以,硬件上 GPIO 控制器有中断能力,设备树中声明两个属性即可
第一个参数是什么? 中断号或 GPIO 引脚编号,如 RK_PB5 = 37
如何确定第一个参数? 从芯片手册、原理图、或参考现有 dts 文件
节点状态由谁决定? 最后 include 的文件中对该节点的定义
属性冲突怎么办? 后加载的文件覆盖先加载的
设备树中关于时钟的节点
目前这个知识点还不太了解,后续用到了再来这边进行补充。
CPU节点
单核处理器CPU描述方法
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu"; //指示设备类型为处理器
// 其他属性...
};
}
多核处理器CPU描述方法
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
device_type = "cpu"; //指示设备类型为处理器
compatible = "arm,cortex-a9";
// 其他属性...
};
cpu1: cpu@1 {
device_type = "cpu"; //指示设备类型为处理器
compatible = "arm,cortex-a9";
// 其他属性...
};
}
cpu-map 节点主要用来进行大小核的描述
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&cpu_l0>;
};
core1 {
cpu = <&cpu_l1>;
};
core2 {
cpu = <&cpu_l2>;
};
core3 {
cpu = <&cpu_l3>;
};
};
cluster1 {
core0 {
cpu = <&cpu_b0>;
};
core1 {
cpu = <&cpu_b1>;
};
};
};
上述的节点用的都不是很多,用到的时候再进行详细的解释
GPIO属性
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pmucru PCLK_GPI00>, <&pmucru DBCLK_GPI00>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
ft5x06: ft5x06@38 {
status = "disabled";
compatible = "edt,edt-ft5306";
reg = <0x38>;
touch-gpio = <&gpio0 RK_PB5 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio0>;
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <1280>;
touch_type = <1>;
};
gpio-controller 属性:gpio-controller 属性用于标识当前节点所描述的设备是一个GPIO 控制器。其本身没有特定的属性值,只需出现在节点中即可。
#gpio-cells 属性:#gpio-cells 属性值是一个整数,表示用于GPIO 引脚描述符的单元数,通常值为2
你的 GPIO 控制器节点:
gpio0: gpio@fdd60000 {
gpio-controller;
#gpio-cells = <2>;
};
然后触摸屏节点引用它:
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
你看到的是 3 项:
<&gpio0 RK_PB6 GPIO_ACTIVE_LOW>
但设备树解析时要分成两部分:
<&gpio0 RK_PB6 GPIO_ACTIVE_LOW>
↑ ↑ ↑
phandle cell0 cell1
其中:
部分 是否属于 #gpio-cells 含义
&gpio0 不属于 指向 GPIO 控制器节点的引用,也叫 phandle
RK_PB6 属于 第 1 个 GPIO 参数,表示 GPIO 编号
GPIO_ACTIVE_LOW 属于 第 2 个 GPIO 参数,表示有效电平/标志
所以:
#gpio-cells = <2>;
表示的是 &gpio0 后面还要跟 2 个参数,不是整个尖括号里总共 2 个。
因此:
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
gpio-controller@00000000 {
compatible = "foo";
reg = <0x00000000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <18>;
gpio-reserved-ranges = <0 4>, <12 2>;
gpio-line-names = "MMC-CD", "MMC-WP",
"voD eth", "RST eth", "LED R",
"LED G", "LED B", "col A",
"col B", "col C", "col D",
"NMI button", "Row A", "Row B",
"Row C", "Row D", "poweroff",
"reset";
};
其他属性:ngpios 属性:指定了GPIO 控制器所支持的GPIO 引脚数量。
gpio-reserved-ranges 属性:定义了保留的GPIO范围。
gpio-line-names 属性:定义了GPIO 引脚的名称,以逗号分隔。这里描述的就是ngpios 属
性所指的18 个GPIO 引脚对应的名称
Pinctl属性
通过pinctrl 在设备树中可以设置引脚复用关系,pinctrl 的语法由客户端和服务端两个部分
构成。
客户端代码格式是固定的,通过pinctrl-names 和pinctrl-<N>属性完成
客户端常见的三种使用模式
node {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1>;
}
node {
pinctrl-names = "default", "wake up";
pinctrl-0 = <&pinctrl_hog_1>;
pinctrl-1 = <&pinctrl_hog_2>;
}
node {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1 &pinctrl_hog_2>;
}
服务端
服务端是设备树中定义引脚配置的部分,不同处理器其服务端代码格式是不同的