概述
在掌握了设备树基础知识后,本文将深入介绍设备树的高级特性,包括overlay机制、pinctrl配置、时钟管理、中断控制器等内容,帮助开发者更好地理解和使用设备树。
一、Device Tree Overlay
1.1 Overlay概念
Overlay允许在不修改主设备树的情况下,动态添加或修改设备树节点,非常适合模块化硬件配置。
1.2 Overlay语法
// rk3588-overlay-example.dts
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
__overlay__ {
status = "okay";
sensor@48 {
compatible = "ti,tmp102";
reg = <0x48>;
};
};
};
fragment@1 {
target-path = "/";
__overlay__ {
custom_device {
compatible = "custom,device";
status = "okay";
};
};
};
};
1.3 编译Overlay
# arch/arm64/boot/dts/rockchip/Makefile
dtbo-$(CONFIG_ARCH_ROCKCHIP) += rk3588-overlay-example.dtbo
# 编译命令
make dtbs
1.4 应用Overlay
# 方法1:通过bootloader
setenv overlay_file rk3588-overlay-example.dtbo
saveenv
reboot
# 方法2:运行时应用(需要内核支持)
mkdir /sys/kernel/config/device-tree/overlays/custom
cat rk3588-overlay-example.dtbo > /sys/kernel/config/device-tree/overlays/custom/dtbo
二、Pinctrl子系统
2.1 Pinctrl基础
Pinctrl用于管理引脚复用和配置。
&pinctrl {
// 定义引脚组
uart1 {
uart1m0_xfer: uart1m0-xfer {
rockchip,pins =
// bank pin func pull
<3 RK_PA0 4 &pcfg_pull_up>, // UART1_TX
<3 RK_PA1 4 &pcfg_pull_up>; // UART1_RX
};
uart1m0_ctsn: uart1m0-ctsn {
rockchip,pins =
<3 RK_PA2 4 &pcfg_pull_none>; // UART1_CTS
};
uart1m0_rtsn: uart1m0-rtsn {
rockchip,pins =
<3 RK_PA3 4 &pcfg_pull_none>; // UART1_RTS
};
};
// 自定义GPIO配置
custom_pins {
custom_gpio_pins: custom-gpio-pins {
rockchip,pins =
<1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>,
<1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>,
<1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
2.2 引脚配置参数
// 预定义的配置
&pcfg_pull_up {
bias-pull-up;
};
&pcfg_pull_down {
bias-pull-down;
};
&pcfg_pull_none {
bias-disable;
};
// 自定义配置
pcfg_custom: pcfg-custom {
bias-pull-up;
drive-strength = <8>; // 驱动强度:2/4/8/12 mA
input-enable;
output-high;
};
2.3 在设备节点中使用
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn &uart1m0_rtsn>;
};
// 多状态配置
&i2c1 {
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c1_xfer>;
pinctrl-1 = <&i2c1_sleep>;
};
三、时钟管理
3.1 时钟树结构
// 时钟控制器
cru: clock-controller@fd7c0000 {
compatible = "rockchip,rk3588-cru";
reg = <0x0 0xfd7c0000 0x0 0x5c000>;
#clock-cells = <1>;
#reset-cells = <1>;
rockchip,grf = <&sys_grf>;
};
// 时钟定义
clocks {
xin24m: xin24m {
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "xin24m";
#clock-cells = <0>;
};
xin32k: xin32k {
compatible = "fixed-clock";
clock-frequency = <32768>;
clock-output-names = "xin32k";
#clock-cells = <0>;
};
};
3.2 设备使用时钟
&uart1 {
status = "okay";
clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
clock-names = "baudclk", "apb_pclk";
};
&i2c1 {
status = "okay";
clocks = <&cru CLK_I2C1>;
clock-names = "i2c";
};
// 多时钟源
&spi0 {
status = "okay";
clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>;
clock-names = "spiclk", "apb_pclk";
assigned-clocks = <&cru CLK_SPI0>;
assigned-clock-rates = <200000000>;
};
3.3 时钟频率设置
&cpu_l0 {
operating-points-v2 = <&cluster0_opp_table>;
};
cluster0_opp_table: opp-table-0 {
compatible = "operating-points-v2";
opp-shared;
opp-408000000 {
opp-hz = /bits/ 64 <408000000>;
opp-microvolt = <850000>;
clock-latency-ns = <40000>;
};
opp-816000000 {
opp-hz = /bits/ 64 <816000000>;
opp-microvolt = <850000>;
};
opp-1416000000 {
opp-hz = /bits/ 64 <1416000000>;
opp-microvolt = <950000>;
};
};
四、中断控制器
4.1 GIC配置
gic: interrupt-controller@fe600000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
interrupt-controller;
reg = <0x0 0xfe600000 0 0x10000>, // GICD
<0x0 0xfe680000 0 0x100000>; // GICR
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
};
4.2 设备中断配置
&uart1 {
status = "okay";
interrupts = <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
};
// GPIO中断
&gpio1 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
};
// 使用GPIO中断
custom_device {
compatible = "custom,device";
interrupt-parent = <&gpio1>;
interrupts = <RK_PA0 IRQ_TYPE_EDGE_FALLING>;
};
4.3 中断类型
// 中断触发类型
#define IRQ_TYPE_NONE 0
#define IRQ_TYPE_EDGE_RISING 1
#define IRQ_TYPE_EDGE_FALLING 2
#define IRQ_TYPE_EDGE_BOTH 3
#define IRQ_TYPE_LEVEL_HIGH 4
#define IRQ_TYPE_LEVEL_LOW 8
五、电源管理
5.1 电源域配置
power: power-controller {
compatible = "rockchip,rk3588-power-controller";
#power-domain-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
pd_gpu {
reg = <RK3588_PD_GPU>;
clocks = <&cru ACLK_GPU>,
<&cru PCLK_GPU_ROOT>;
pm_qos = <&qos_gpu_m0>,
<&qos_gpu_m1>;
};
pd_npu {
reg = <RK3588_PD_NPU>;
clocks = <&cru HCLK_NPU_ROOT>,
<&cru PCLK_NPU_ROOT>;
};
};
5.2 设备电源域
&gpu {
power-domains = <&power RK3588_PD_GPU>;
};
&npu {
power-domains = <&power RK3588_PD_NPU>;
};
5.3 电源管理策略
&cpu_l0 {
cpu-supply = <&vdd_cpu_lit_s0>;
dynamic-power-coefficient = <100>;
};
&cpu_b0 {
cpu-supply = <&vdd_cpu_big0_s0>;
dynamic-power-coefficient = <390>;
};
六、DMA配置
6.1 DMA控制器
dmac0: dma-controller@fea10000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0xfea10000 0x0 0x4000>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
#dma-cells = <1>;
arm,pl330-periph-burst;
clocks = <&cru ACLK_DMAC0>;
clock-names = "apb_pclk";
};
6.2 设备使用DMA
&spi0 {
status = "okay";
dmas = <&dmac0 14>, <&dmac0 15>;
dma-names = "tx", "rx";
};
&uart1 {
status = "okay";
dmas = <&dmac0 8>, <&dmac0 9>;
dma-names = "tx", "rx";
};
七、内存管理
7.1 内存节点
memory@a00000 {
device_type = "memory";
reg = <0x0 0x00a00000 0x0 0x7f600000>;
};
// 保留内存
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
// CMA内存
linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0x0 0x10000000>; // 256MB
alignment = <0x0 0x2000>;
linux,cma-default;
};
// 专用内存
ramoops@110000 {
compatible = "ramoops";
reg = <0x0 0x110000 0x0 0xf0000>;
record-size = <0x20000>;
console-size = <0x80000>;
ftrace-size = <0x00000>;
pmsg-size = <0x50000>;
};
};
7.2 IOMMU配置
iommu: iommu@fd5f0000 {
compatible = "rockchip,rk3588-iommu";
reg = <0x0 0xfd5f0000 0x0 0x100>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
#iommu-cells = <0>;
status = "okay";
};
&vop {
iommus = <&iommu>;
};
八、调试技巧
8.1 查看设备树
# 查看编译后的设备树
dtc -I dtb -O dts -o output.dts /boot/dtb/rk3588.dtb
# 查看运行时设备树
cat /sys/firmware/devicetree/base/model
ls -la /sys/firmware/devicetree/base/
# 查看特定节点
cat /sys/firmware/devicetree/base/compatible
8.2 验证设备树
# 编译时检查
make dtbs_check
# 运行时检查
dmesg | grep -i "device tree"
dmesg | grep -i "of_platform"
8.3 常用调试命令
# 查看platform设备
ls /sys/bus/platform/devices/
# 查看设备驱动绑定
cat /sys/bus/platform/devices/*/driver
# 查看GPIO状态
cat /sys/kernel/debug/gpio
# 查看时钟树
cat /sys/kernel/debug/clk/clk_summary
# 查看中断统计
cat /proc/interrupts
九、最佳实践
9.1 模块化设计
// 主设备树
#include "rk3588.dtsi"
#include "rk3588-pinctrl.dtsi"
// 板级设备树
/ {
model = "Custom RK3588 Board";
compatible = "custom,rk3588", "rockchip,rk3588";
};
// 包含功能模块
#include "rk3588-custom-display.dtsi"
#include "rk3588-custom-audio.dtsi"
#include "rk3588-custom-network.dtsi"
9.2 使用宏定义
// 定义常用宏
#define CUSTOM_GPIO_LED <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>
#define CUSTOM_GPIO_KEY <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>
/ {
leds {
compatible = "gpio-leds";
led-power {
gpios = CUSTOM_GPIO_LED;
default-state = "on";
};
};
keys {
compatible = "gpio-keys";
key-power {
gpios = CUSTOM_GPIO_KEY;
linux,code = <KEY_POWER>;
};
};
};
9.3 注释规范
/*
* Custom Device Configuration
* Author: xxx
* Date: 2024-01-14
* Description: Configuration for custom peripheral devices
*/
&i2c1 {
status = "okay";
clock-frequency = <400000>; // 400kHz fast mode
/* Temperature sensor */
sensor@48 {
compatible = "ti,tmp102";
reg = <0x48>;
/* Alert pin configuration */
interrupt-parent = <&gpio1>;
interrupts = <RK_PA0 IRQ_TYPE_EDGE_FALLING>;
};
};
十、常见问题
10.1 设备树编译失败
# 错误:语法错误
Error: xxx.dts:123: syntax error
# 解决:检查语法
# 1. 检查括号匹配
# 2. 检查分号
# 3. 检查引用是否存在
10.2 设备未被识别
# 检查compatible属性
grep -r "compatible" drivers/
# 检查设备树节点
ls /sys/firmware/devicetree/base/
# 检查驱动加载
lsmod | grep driver_name
10.3 引脚复用冲突
# 查看引脚使用情况
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins
# 查看GPIO占用
cat /sys/kernel/debug/gpio
总结
本文深入介绍了设备树的高级特性:
- Overlay机制 - 动态修改设备树
- Pinctrl配置 - 引脚复用和配置
- 时钟管理 - 时钟树和频率设置
- 中断控制 - GIC和GPIO中断
- 电源管理 - 电源域和策略
- DMA配置 - DMA控制器使用
- 内存管理 - 内存节点和IOMMU
掌握这些高级特性,可以更灵活地配置硬件资源,提高开发效率。