【RK3588 Android12】设备树DTS进阶

概述

在掌握了设备树基础知识后,本文将深入介绍设备树的高级特性,包括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

总结

本文深入介绍了设备树的高级特性:

  1. Overlay机制 - 动态修改设备树
  2. Pinctrl配置 - 引脚复用和配置
  3. 时钟管理 - 时钟树和频率设置
  4. 中断控制 - GIC和GPIO中断
  5. 电源管理 - 电源域和策略
  6. DMA配置 - DMA控制器使用
  7. 内存管理 - 内存节点和IOMMU

掌握这些高级特性,可以更灵活地配置硬件资源,提高开发效率。

参考资料

相关推荐
小痞同学2 小时前
【铁头山羊STM32】HAL库 5.SPI部分
stm32·单片机·嵌入式硬件
蓬荜生灰2 小时前
STM32(5)-- 新建寄存器版工程
stm32·单片机·嵌入式硬件
大神与小汪3 小时前
STM32上进行Unix时间戳转换
stm32·嵌入式硬件·unix
嗯嗯=3 小时前
STM32单片机学习篇1
stm32·单片机·嵌入式硬件
恶魔泡泡糖3 小时前
51单片机I-O扩展2
单片机·嵌入式硬件·51单片机
梁洪飞4 小时前
kernel 内存知识
linux·arm开发·嵌入式硬件·arm
纳祥科技4 小时前
硬核拆解:一款DP转3VGA+音频输出分配器,3屏同步输出
单片机·嵌入式硬件·音视频·拆解
ElfBoard5 小时前
ElfBoard技术贴|如何在ELF-RK3506开发板上构建AI编程环境
c语言·开发语言·单片机·嵌入式硬件·智能路由器·ai编程·嵌入式开发
橙露5 小时前
STM32 单片机实战:基于 HAL 库的串口通信与中断处理详解
stm32·单片机·嵌入式硬件