RK3568设备树实战:从零开始手把手教你修改DTS文件(附常见外设节点配置)

RK3568设备树实战:从零开始手把手教你修改DTS文件(附常见外设节点配置)

如果你刚开始接触RK3568这类嵌入式Linux开发板,可能会对“设备树”这个词感到既熟悉又陌生。它不像C语言代码那样直观,也不像硬件电路图那样具体,但却是连接硬件与Linux内核的桥梁。我最初接触设备树时,也经历过一段迷茫期——面对动辄数千行的DTS文件,不知从何下手。后来在几个实际项目中反复折腾,才逐渐摸清了门道。这篇文章,就是把我踩过的坑、总结的经验,用最直白的方式分享给你。

设备树本质上是一种描述硬件的数据结构,它告诉Linux内核:“这块板子上有什么”。对于RK3568这样的SoC,其外设资源(如UART、I2C、SPI控制器)是固定的,但具体如何连接到外部器件(如Flash、传感器、PHY芯片),则因板而异。设备树就是用来描述这些板级差异的。你不用再像以前那样,为了支持一块新板子而去修改内核源码、重新编译;现在只需修改或新增一个DTS文件,内核就能自动识别并加载对应驱动。

这篇文章面向的是已经具备一定Linux驱动基础,但设备树经验尚浅的开发者。我会从最基础的DTS语法讲起,带你一步步为一块自定义的RK3568板子添加CPU、UART、I2C等节点,并重点解析reg地址映射、compatible匹配规则这些核心概念。最后,我会用两个真实的配置示例——SPI-NOR Flash和以太网PHY——来演示如何将理论转化为实践。目标是让你读完就能动手,为自己的硬件定制设备树。

1. 设备树基础:从概念到文件结构

在深入修改DTS文件之前,我们得先搞清楚设备树到底是什么,以及它在RK3568开发中扮演什么角色。简单来说,设备树(Device Tree)是一种描述硬件组件及其连接关系的数据结构,采用一种名为DTS(Device Tree Source)的文本格式编写。这个描述文件会被编译成DTB(Device Tree Blob)二进制格式,由Bootloader(如U-Boot)在启动内核时传递给内核。内核解析DTB后,就能知道当前运行在什么样的硬件平台上,从而正确初始化和驱动各类外设。

为什么需要设备树?在设备树普及之前,内核源码中充斥着大量板级描述代码(位于arch/arm/mach-*目录)。每支持一款新板子,就要在内核中添加或修改这些代码,导致内核“虚胖”,且移植工作繁琐。设备树将硬件描述从内核中剥离出来,实现了硬件描述与内核代码的解耦。对于RK3568,瑞芯微官方提供了rk3568.dtsi这样的SoC级描述文件,描述了芯片内部的所有公共资源。我们开发者要做的,就是基于这个文件,编写或修改板级DTS文件,描述我们自己的硬件连接。

一个典型的RK3568设备树文件结构如下所示。它通常由板级DTS文件(如rk3568-myboard.dts)和引用的SoC级DTSI文件(如rk3568.dtsi)共同构成。

// 板级DTS文件:rk3568-myboard.dts
/dts-v1/;
#include "rk3568.dtsi"        // 包含SoC级定义
#include "rk3568-pinctrl.dtsi" // 包含引脚复用定义

/ {
    model = "My Custom RK3568 Board";
    compatible = "mycompany,rk3568-myboard", "rockchip,rk3568";

    // 板级特有节点和属性定义从这里开始
    chosen {
        bootargs = "console=ttyS2,1500000 earlycon=uart8250,mmio32,0xfe660000";
    };

    // 例如,定义板载LED
    leds {
        compatible = "gpio-leds";
        led0 {
            label = "heartbeat";
            gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
            linux,default-trigger = "heartbeat";
        };
    };
};

// 对SoC已有节点进行覆盖或追加配置
&uart2 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&uart2m0_xfer>;
};

&i2c3 {
    status = "okay";
    clock-frequency = <400000>;
    // 可以在这里挂载I2C设备,例如EEPROM
    eeprom@50 {
        compatible = "atmel,24c02";
        reg = <0x50>;
    };
};

关键点解析

  • /dts-v1/;:声明设备树版本,必须放在文件开头。
  • #include:用于包含其他.dtsi.h文件。.dtsi类似于C语言的头文件,包含可重用的公共定义。
  • 根节点 /:所有设备的父节点。model属性描述板子型号,compatible属性是内核匹配板子的关键,它是一组字符串列表,内核会按顺序尝试匹配。
  • 节点标签与引用&uart2表示引用标签为uart2的节点(该节点定义在rk3568.dtsi中)。这是修改或追加现有节点配置的标准方式,避免了直接修改公共文件。
  • status属性:这是你最常修改的属性之一。"okay"表示启用该设备,"disabled"表示禁用。很多外设在SoC级定义中默认是"disabled",需要在板级文件中显式启用。

设备树在系统中的直观体现是/proc/device-tree目录。内核启动后,会将解析的设备树以目录结构的形式呈现于此。你可以通过cat命令查看节点的属性值,这在实际调试中非常有用。

# 查看根节点的compatible属性,确认板子匹配
cat /proc/device-tree/compatible
# 查看某个节点(如i2c3)的状态
cat /proc/device-tree/i2c3/status

2. 核心语法与属性详解:读懂并编写节点

理解了文件结构,我们再来深入看看构成设备树的基本单元:节点(Node)和属性(Property)。每个节点描述一个设备或总线,属性则是描述该设备的键值对。

2.1 节点命名与结构

一个完整的节点定义如下:

node_label: node_name@unit_address {
    property1 = value1;
    property2 = value2;
    child_node {
        // 子节点定义
    };
};
  • node_label(标签):可选项,用于在其他地方引用该节点,格式为&label。例如,&i2c0就引用了标签为i2c0的节点。使用标签是设备树编程的最佳实践,它让引用变得清晰且易于维护。
  • node_name(节点名):描述设备类型,如i2cspiuart
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值