在嵌入式Linux和Android开发领域,设备树(Device Tree)已经成为硬件描述的事实标准。对于RK3588这类高性能处理器平台,设备树更是系统启动和硬件初始化的核心配置文件。我第一次接触RK3588的设备树配置时,发现它就像一张精确的硬件地图,告诉内核哪里有什么资源、如何访问这些资源。
设备树源文件(DTS,Device Tree Source)采用一种类似JSON的树状结构语法,最终会被编译成二进制格式的DTB(Device Tree Blob)供内核使用。在RK3588 Android12的开发环境中,设备树主要承担三大职责:
提示:RK3588的设备树文件通常位于内核源码的arch/arm64/boot/dts/rockchip目录下,文件名遵循rk3588-.dtsi或rk3588-.dts的命名规则。
RK3588平台的设备树采用模块化设计,通常包含以下关键文件:
基础定义文件:
板级文件:
模块覆盖文件:
dts复制// 典型节点结构示例
&i2c1 {
status = "okay";
clock-frequency = <400000>;
sensor@0d {
compatible = "company,sensor-model";
reg = <0x0d>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PA4 IRQ_TYPE_LEVEL_HIGH>;
};
};
节点(Node):
/表示根节点,&引用已有节点cpus、memory、pmu等属性(Property):
compatible、reg、interruptsrockchip,xxx系列数值表示:
clock-frequency = <1000000>reg = <0xff000000 0x1000000>pinctrl-0 = <&uart0m1_xfer &uart0m1_ctsn>注意:RK3588使用#address-cells=<2>和#size-cells=<2>,与其他平台常见的<1>不同,这是由于其64位地址空间特性决定的。
RK3588采用4xCortex-A76 + 4xCortex-A55的big.LITTLE架构,设备树需要正确定义CPU拓扑:
dts复制cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&cpu_b0>;
};
// ...其他核心
};
cluster1 {
core0 {
cpu = <&cpu_l0>;
};
// ...其他核心
};
};
cpu_b0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a76";
reg = <0x0 0x0>;
enable-method = "psci";
capacity-dmips-mhz = <1024>;
};
// ...其他CPU节点
};
以MIPI-CSI摄像头接口为例:
dts复制&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
csi_dphy_input0: endpoint@0 {
reg = <0>;
remote-endpoint = <&sensor_out>;
data-lanes = <1 2 3 4>;
};
};
};
};
&i2c1 {
imx415: sensor@1a {
compatible = "sony,imx415";
reg = <0x1a>;
clocks = <&cru CLK_MIPI_CAMARAOUT_M1>;
clock-names = "xvclk";
port {
sensor_out: endpoint {
remote-endpoint = <&csi_dphy_input0>;
data-lanes = <1 2 3 4>;
};
};
};
};
RK3588具有复杂的电源域划分:
dts复制&power {
pd_npu: pd_npu@RK3588_PD_NPU {
reg = <RK3588_PD_NPU>;
#power-domain-cells = <0>;
};
// ...其他电源域
};
&npu {
power-domains = <&power RK3588_PD_NPU>;
status = "okay";
};
bash复制# 编译命令
./scripts/dtc/dtc -I dts -O dtb -o rk3588-evb.dtb arch/arm64/boot/dts/rockchip/rk3588-evb.dts
# 反编译命令
./scripts/dtc/dtc -I dtb -O dts -o extracted.dts rk3588-evb.dtb
查看加载的设备树:
bash复制adb shell cat /proc/device-tree/model
检查特定节点:
bash复制adb shell ls /proc/device-tree/soc/i2c@fea90000
内核日志过滤:
bash复制adb shell dmesg | grep -i dts
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 外设无法识别 | compatible字符串不匹配 | 核对芯片手册与驱动代码 |
| 寄存器访问失败 | reg属性地址/长度错误 | 检查数据手册寄存器映射 |
| 中断不触发 | interrupts配置错误 | 验证GPIO引脚和中断类型 |
| 时钟异常 | clock-frequency超出范围 | 核对硬件规格书限制值 |
| 驱动加载失败 | status未设为"okay" | 检查节点状态属性 |
Android12对设备树处理的主要变化:
典型修改示例:
dts复制/ {
firmware {
android {
compatible = "android,firmware";
fstab {
compatible = "android,fstab";
system {
compatible = "android,system";
dev = "/dev/block/by-name/system";
type = "ext4";
mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
fsmgr_flags = "wait,avb";
};
};
};
};
};
各厂商通常会添加自定义属性:
dts复制&display_subsystem {
rockchip,disable-mmu-recovery;
rockchip,dummy-lcd-enable;
rockchip,reset-merge;
};
&route_hdmi {
rockchip,dual-channel;
status = "okay";
};
dts复制/ {
#ifdef CONFIG_CAMERA_SUPPORT
camera {
compatible = "rockchip,rk3588-camera";
status = "okay";
};
#endif
};
动态加载设备树片段:
bash复制adb push my_overlay.dtbo /vendor/etc/overlays/
adb shell echo 1 > /sys/kernel/config/device-tree/overlays/enable
dts复制/ {
compatible = "rockchip,rk3588", "rockchip,rk35xx";
board_revision: board-revision {
compatible = "nvmem-cells";
#address-cells = <1>;
#size-cells = <1>;
reg = <0xff00 0x1>;
bits = <0 3>;
};
};
在实际项目中,我发现RK3588的设备树配置有几个特别需要注意的点:首先是PCIe和USB3.0的PHY配置容易冲突,需要严格按照参考设计配置;其次是NPU和GPU的电源域管理必须正确,否则会导致性能下降;最后是MIPI显示接口的lane分配必须与硬件布线完全一致,差一个引脚都会导致显示异常。建议每次修改设备树后,先用dtc命令检查语法,再通过adb观察内核启动日志,可以节省大量调试时间。