Linux设备树
Linux设备树详解及实例
1. 设备树概述
设备树(Device Tree)是一种描述硬件配置的数据结构,用于将硬件信息从内核代码中分离出来。
1.1 设备树基本概念
- 源文件:.dts- 设备树源文件,.dtsi- 包含文件
- 编译文件:.dtb- 设备树二进制文件
- 节点:描述设备或总线的基本单位
- 属性:描述设备的特性、地址、中断等
1.2 设备树优势
- 硬件信息与内核代码分离
- 支持同一内核镜像在不同硬件平台运行
- 简化BSP(板级支持包)开发
2. 设备树语法基础
2.1 基本结构
// 示例:简单的设备树
/dts-v1/;
/ {
    // 根节点
    compatible = "vendor,board-name", "vendor,board-family";
    model = "Vendor Board Version 1.0";
    #address-cells = <1>;  // 子节点地址用1个32位数字表示
    #size-cells = <1>;     // 子节点大小用1个32位数字表示
    
    // CPU节点
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        
        cpu@0 {
            compatible = "arm,cortex-a53";
            device_type = "cpu";
            reg = <0x0>;
            clock-frequency = <1200000000>;
        };
    };
    
    // 内存节点
    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x40000000>; // 起始地址0x80000000,大小1GB
    };
    
    // 保留内存
    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
        
        linux,cma {
            compatible = "shared-dma-pool";
            reusable;
            size = <0x10000000>; // 256MB
            alignment = <0x2000>;
            linux,cma-default;
        };
    };
};
2.2 常用属性详解
/ {
    // 兼容性属性 - 最重要的属性
    compatible = "vendor,board", "vendor,soc", "arm,board";
    
    // 模型描述
    model = "Vendor Development Board";
    
    // 地址和大小单元定义
    #address-cells = <1>;  // 地址用1个cell表示
    #size-cells = <1>;     // 大小用1个cell表示
    
    // 中断控制器属性
    interrupt-parent = <&intc>;  // 指向中断控制器
    
    // 选择总线
    chosen {
        bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait";
        stdout-path = &uart0;
    };
    
    // 别名
    aliases {
        serial0 = &uart0;
        ethernet0 = ð0;
        mmc0 = &sdhci0;
    };
};
3. 常用设备节点实例
3.1 UART串口设备
/ {
    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges;
        
        uart0: serial@10000000 {
            compatible = "vendor,uart", "ns16550a";
            reg = <0x10000000 0x1000>;
            interrupts = <0 10 4>;        // SPI 10, 电平触发
            clocks = <&clk_uart>;
            clock-frequency = <115200>;
            status = "okay";
            
            // FIFO设置
            fifo-size = <16>;
            auto-flow-control;
        };
        
        uart1: serial@10001000 {
            compatible = "vendor,uart";
            reg = <0x10001000 0x1000>;
            interrupts = <0 11 4>;
            clocks = <&clk_uart>;
            status = "disabled";          // 默认禁用
        };
    };
};
3.2 I2C控制器及设备
/ {
    soc {
        i2c0: i2c@20000000 {
            compatible = "vendor,i2c";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <0x20000000 0x1000>;
            interrupts = <0 20 4>;
            clocks = <&clk_i2c>;
            clock-frequency = <100000>;   // 标准模式100kHz
            status = "okay";
            
            // I2C设备:EEPROM
            eeprom@50 {
                compatible = "atmel,24c02";
                reg = <0x50>;
                pagesize = <16>;
            };
            
            // I2C设备:温度传感器
            temp_sensor: lm75@48 {
                compatible = "national,lm75";
                reg = <0x48>;
            };
            
            // I2C设备:RTC
            rtc: ds1339@68 {
                compatible = "dallas,ds1339";
                reg = <0x68>;
            };
        };
        
        i2c1: i2c@20001000 {
            compatible = "vendor,i2c";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <0x20001000 0x1000>;
            interrupts = <0 21 4>;
            clocks = <&clk_i2c>;
            clock-frequency = <400000>;   // 快速模式400kHz
            status = "okay";
            
            // I2C设备:音频编解码器
            codec: wm8960@1a {
                compatible = "wlf,wm8960";
                reg = <0x1a>;
                #sound-dai-cells = <0>;
            };
        };
    };
};
3.3 SPI控制器及设备
/ {
    soc {
        spi0: spi@30000000 {
            compatible = "vendor,spi";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <0x30000000 0x1000>;
            interrupts = <0 30 4>;
            clocks = <&clk_spi>;
            num-cs = <2>;                // 2个片选信号
            status = "okay";
            
            // SPI Flash设备
            flash@0 {
                compatible = "jedec,spi-nor";
                reg = <0>;               // CS0
                spi-max-frequency = <50000000>;
                #address-cells = <1>;
                #size-cells = <1>;
                
                partition@0 {
                    label = "bootloader";
                    reg = <0x00000000 0x00100000>;
                };
                partition@100000 {
                    label = "kernel";
                    reg = <0x00100000 0x00500000>;
                };
                partition@600000 {
                    label = "rootfs";
                    reg = <0x00600000 0x01a00000>;
                };
            };
            
            // SPI ADC设备
            adc@1 {
                compatible = "ti,adc128s052";
                reg = <1>;               // CS1
                spi-max-frequency = <1000000>;
                vref-supply = <&vref_reg>;
            };
        };
    };
};
3.4 GPIO控制器
/ {
    soc {
        gpio0: gpio@40000000 {
            compatible = "vendor,gpio";
            reg = <0x40000000 0x1000>;
            interrupts = <0 40 4>;
            #gpio-cells = <2>;
            gpio-controller;
            #interrupt-cells = <2>;
            interrupt-controller;
            ngpios = <32>;
            status = "okay";
        };
        
        gpio1: gpio@40001000 {
            compatible = "vendor,gpio";
            reg = <0x40001000 0x1000>;
            interrupts = <0 41 4>;
            #gpio-cells = <2>;
            gpio-controller;
            #interrupt-cells = <2>;
            interrupt-controller;
            ngpios = <16>;
            status = "okay";
        };
    };
};
3.5 以太网控制器
/ {
    soc {
        eth0: ethernet@50000000 {
            compatible = "vendor,eth";
            reg = <0x50000000 0x1000>;
            interrupts = <0 50 4>;
            clocks = <&clk_eth>;
            phy-mode = "rgmii";
            phy-handle = <&phy0>;
            status = "okay";
            
            mdio {
                #address-cells = <1>;
                #size-cells = <0>;
                
                phy0: ethernet-phy@0 {
                    reg = <0>;
                    reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
                    reset-assert-us = <10000>;
                    reset-deassert-us = <10000>;
                };
            };
        };
    };
};
4. 时钟和电源管理
4.1 时钟控制器
/ {
    clocks {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
        
        osc24m: osc24m {
            compatible = "fixed-clock";
            #clock-cells = <0>;
            clock-frequency = <24000000>;
            clock-output-names = "osc24m";
        };
        
        clk_pll: pll@10010000 {
            compatible = "vendor,pll";
            reg = <0x10010000 0x1000>;
            #clock-cells = <1>;
            clocks = <&osc24m>;
            clock-output-names = "pll_cpu", "pll_ddr", "pll_periph";
        };
        
        clk_uart: uart_clk {
            compatible = "fixed-factor-clock";
            #clock-cells = <0>;
            clocks = <&clk_pll 2>;
            clock-div = <4>;
            clock-mult = <1>;
            clock-output-names = "uart_clk";
        };
    };
};
4.2 电源管理
/ {
    regulators {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <0>;
        
        reg_3v3: regulator@0 {
            compatible = "regulator-fixed";
            reg = <0>;
            regulator-name = "3V3";
            regulator-min-microvolt = <3300000>;
            regulator-max-microvolt = <3300000>;
            regulator-always-on;
        };
        
        reg_1v8: regulator@1 {
            compatible = "regulator-fixed";
            reg = <1>;
            regulator-name = "1V8";
            regulator-min-microvolt = <1800000>;
            regulator-max-microvolt = <1800000>;
            gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
            enable-active-high;
        };
        
        vref_reg: regulator@2 {
            compatible = "regulator-fixed";
            reg = <2>;
            regulator-name = "vref";
            regulator-min-microvolt = <2500000>;
            regulator-max-microvolt = <2500000>;
        };
    };
};
5. 引脚控制(Pinctrl)
5.1 引脚复用配置
/ {
    soc {
        pinctrl: pinctrl@60000000 {
            compatible = "vendor,pinctrl";
            reg = <0x60000000 0x1000>;
            
            // UART0引脚配置
            uart0_pins: uart0-pins {
                pins = "PA0", "PA1";
                function = "uart0";
                bias-disable;
            };
            
            // I2C0引脚配置
            i2c0_pins: i2c0-pins {
                pins = "PA2", "PA3";
                function = "i2c0";
                bias-pull-up;
            };
            
            // SPI0引脚配置
            spi0_pins: spi0-pins {
                pins = "PA4", "PA5", "PA6", "PA7";
                function = "spi0";
                bias-disable;
            };
            
            // 以太网引脚配置
            eth_pins: eth-pins {
                pins = "PB0", "PB1", "PB2", "PB3", 
                       "PB4", "PB5", "PB6", "PB7",
                       "PB8", "PB9", "PB10", "PB11";
                function = "eth";
                drive-strength = <40>;
                bias-disable;
            };
            
            // LED引脚配置
            led_pins: led-pins {
                pins = "PC0", "PC1", "PC2";
                function = "gpio";
                bias-pull-up;
                output-high;
            };
        };
        
        // 在设备节点中引用pinctrl
        uart0: serial@10000000 {
            compatible = "vendor,uart";
            reg = <0x10000000 0x1000>;
            interrupts = <0 10 4>;
            clocks = <&clk_uart>;
            pinctrl-names = "default";
            pinctrl-0 = <&uart0_pins>;
            status = "okay";
        };
        
        i2c0: i2c@20000000 {
            compatible = "vendor,i2c";
            reg = <0x20000000 0x1000>;
            interrupts = <0 20 4>;
            clocks = <&clk_i2c>;
            pinctrl-names = "default";
            pinctrl-0 = <&i2c0_pins>;
            status = "okay";
        };
    };
};
6. 完整开发板实例
6.1 完整的开发板设备树
// vendor-board-v1.dts
/dts-v1/;
#include "vendor-soc.dtsi"  // 包含SoC通用定义
/ {
    model = "Vendor Development Board V1.0";
    compatible = "vendor,board-v1", "vendor,soc";
    
    // 内存配置
    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x40000000>; // 1GB RAM
    };
    
    // 保留内存
    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
        
        // CMA区域
        linux,cma {
            compatible = "shared-dma-pool";
            reusable;
            size = <0x10000000>; // 256MB
            alignment = <0x2000>;
            linux,cma-default;
        };
        
        // DSP专用内存
        dsp_reserved: dsp@88000000 {
            reg = <0x88000000 0x08000000>; // 128MB
            no-map;
        };
    };
    
    // 启动参数
    chosen {
        bootargs = "console=ttyS0,115200 earlycon root=/dev/mmcblk0p2 rootwait";
        stdout-path = "serial0:115200n8";
    };
    
    // 别名
    aliases {
        serial0 = &uart0;
        serial1 = &uart1;
        ethernet0 = ð0;
        mmc0 = &sdhci0;
        spi0 = &spi0;
        i2c0 = &i2c0;
        i2c1 = &i2c1;
    };
    
    // LED定义
    leds {
        compatible = "gpio-leds";
        
        led-0 {
            label = "heartbeat";
            gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
            linux,default-trigger = "heartbeat";
            default-state = "off";
        };
        
        led-1 {
            label = "mmc0";
            gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
            linux,default-trigger = "mmc0";
            default-state = "off";
        };
        
        led-2 {
            label = "cpu";
            gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
            linux,default-trigger = "cpu0";
            default-state = "off";
        };
    };
    
    // 按键定义
    gpio-keys {
        compatible = "gpio-keys";
        
        button-0 {
            label = "User Button 0";
            gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
            linux,code = <KEY_PROG1>;
        };
        
        button-1 {
            label = "User Button 1";
            gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
            linux,code = <KEY_PROG2>;
        };
    };
    
    // 背光控制
    backlight: backlight {
        compatible = "pwm-backlight";
        pwms = <&pwm 0 50000 0>; // PWM通道0,50kHz
        brightness-levels = <0 4 8 16 32 64 128 255>;
        default-brightness-level = <6>;
        enable-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
    };
    
    // 音频编解码器
    sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "Vendor-Board-Sound";
        simple-audio-card,format = "i2s";
        simple-audio-card,mclk-fs = <256>;
        
        simple-audio-card,cpu {
            sound-dai = <&i2s0>;
        };
        
        simple-audio-card,codec {
            sound-dai = <&codec>;
        };
    };
};
// 启用/禁用具体设备
&uart0 {
    pinctrl-names = "default";
    pinctrl-0 = <&uart0_pins>;
    status = "okay";
};
&uart1 {
    status = "disabled"; // 默认禁用UART1
};
&i2c0 {
    pinctrl-names = "default";
    pinctrl-0 = <&i2c0_pins>;
    status = "okay";
    
    // 扩展板上的设备
    expansion_eeprom: eeprom@50 {
        compatible = "atmel,24c02";
        reg = <0x50>;
        pagesize = <16>;
    };
};
&i2c1 {
    pinctrl-names = "default";
    pinctrl-0 = <&i2c1_pins>;
    status = "okay";
    
    // 音频编解码器
    codec: wm8960@1a {
        compatible = "wlf,wm8960";
        reg = <0x1a>;
        #sound-dai-cells = <0>;
    };
};
&spi0 {
    pinctrl-names = "default";
    pinctrl-0 = <&spi0_pins>;
    status = "okay";
    
    flash@0 {
        compatible = "winbond,w25q128", "jedec,spi-nor";
        reg = <0>;
        spi-max-frequency = <50000000>;
        #address-cells = <1>;
        #size-cells = <1>;
        
        partition@0 {
            label = "bootloader";
            reg = <0x000000 0x100000>;
        };
        
        partition@100000 {
            label = "kernel";
            reg = <0x100000 0x500000>;
        };
        
        partition@600000 {
            label = "rootfs";
            reg = <0x600000 0xa00000>;
        };
    };
};
ð0 {
    pinctrl-names = "default";
    pinctrl-0 = <ð_pins>;
    phy-mode = "rgmii";
    status = "okay";
    
    fixed-link {
        speed = <1000>;
        full-duplex;
    };
};
&sdhci0 {
    pinctrl-names = "default";
    pinctrl-0 = <&sdhci0_pins>;
    bus-width = <4>;
    cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
    wp-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
    status = "okay";
};
&usb0 {
    dr_mode = "host";
    status = "okay";
};
&pwm {
    pinctrl-names = "default";
    pinctrl-0 = <&pwm0_pins>;
    status = "okay";
};
7. 设备树驱动实例
7.1 解析设备树的驱动程序
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
struct my_device_data {
    struct device *dev;
    void __iomem *regs;
    struct gpio_desc *reset_gpio;
    struct regulator *vcc_supply;
    int irq;
    u32 clock_frequency;
    const char *device_name;
};
static const struct of_device_id my_device_of_match[] = {
    { .compatible = "vendor,my-device" },
    { .compatible = "vendor,my-device-v2" },
    {},
};
MODULE_DEVICE_TABLE(of, my_device_of_match);
static int my_device_parse_dt(struct platform_device *pdev, 
                             struct my_device_data *data)
{
    struct device_node *np = pdev->dev.of_node;
    int ret;
    
    if (!np) {
        dev_err(&pdev->dev, "No device tree node found\n");
        return -EINVAL;
    }
    
    // 获取设备名称
    ret = of_property_read_string(np, "device-name", &data->device_name);
    if (ret) {
        data->device_name = "default";
    }
    
    // 获取时钟频率
    ret = of_property_read_u32(np, "clock-frequency", &data->clock_frequency);
    if (ret) {
        data->clock_frequency = 1000000; // 默认1MHz
    }
    
    // 获取GPIO
    data->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset", 
                                              GPIOD_OUT_HIGH);
    if (IS_ERR(data->reset_gpio)) {
        return PTR_ERR(data->reset_gpio);
    }
    
    // 获取电源
    data->vcc_supply = devm_regulator_get_optional(&pdev->dev, "vcc");
    if (IS_ERR(data->vcc_supply)) {
        if (PTR_ERR(data->vcc_supply) == -EPROBE_DEFER)
            return -EPROBE_DEFER;
        data->vcc_supply = NULL;
    }
    
    // 获取中断
    data->irq = platform_get_irq(pdev, 0);
    if (data->irq < 0) {
        dev_info(&pdev->dev, "No IRQ specified\n");
    }
    
    return 0;
}
static int my_device_probe(struct platform_device *pdev)
{
    struct my_device_data *data;
    int ret;
    
    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;
    
    data->dev = &pdev->dev;
    
    // 解析设备树
    ret = my_device_parse_dt(pdev, data);
    if (ret)
        return ret;
    
    // 映射寄存器
    data->regs = devm_platform_ioremap_resource(pdev, 0);
    if (IS_ERR(data->regs))
        return PTR_ERR(data->regs);
    
    // 使能电源
    if (data->vcc_supply) {
        ret = regulator_enable(data->vcc_supply);
        if (ret) {
            dev_err(&pdev->dev, "Failed to enable regulator\n");
            return ret;
        }
    }
    
    // 硬件复位
    if (data->reset_gpio) {
        gpiod_set_value_cansleep(data->reset_gpio, 0);
        msleep(10);
        gpiod_set_value_cansleep(data->reset_gpio, 1);
        msleep(100);
    }
    
    platform_set_drvdata(pdev, data);
    
    dev_info(&pdev->dev, "Device %s probed, clock: %u Hz\n",
             data->device_name, data->clock_frequency);
    
    return 0;
}
static int my_device_remove(struct platform_device *pdev)
{
    struct my_device_data *data = platform_get_drvdata(pdev);
    
    if (data->vcc_supply)
        regulator_disable(data->vcc_supply);
    
    return 0;
}
static struct platform_driver my_device_driver = {
    .probe = my_device_probe,
    .remove = my_device_remove,
    .driver = {
        .name = "my-device",
        .of_match_table = my_device_of_match,
    },
};
module_platform_driver(my_device_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Device Tree aware device driver");
8. 设备树编译和调试
8.1 编译设备树
# Makefile示例
DTC = dtc
DTS = vendor-board-v1.dts
DTB = vendor-board-v1.dtb
all: $(DTB)
$(DTB): $(DTS)
    $(DTC) -I dts -O dtb -o $(DTB) $(DTS)
clean:
    rm -f $(DTB)
# 内核中的编译
obj-y += vendor-board-v1.dtb
8.2 设备树调试命令
# 查看设备树
cat /proc/device-tree/model
ls /proc/device-tree/
# 使用dtc工具反编译
dtc -I fs /proc/device-tree
# 查看特定设备
find /proc/device-tree -name "*uart*"
# 内核启动参数添加设备树调试
bootargs="console=ttyS0,115200 earlycon devicetree=debug"
设备树是现代Linux嵌入式系统的核心组成部分,通过合理设计设备树结构,可以创建高度可移植和可维护的硬件描述。掌握设备树语法和驱动程序的设备树解析是嵌入式Linux开发的重要技能。
            本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 恒星不见
        
     评论
            
                匿名评论
                隐私政策
            
            
                你无需删除空行,直接评论以获取最佳展示效果
            
         
            
        
