linux设备树

1.设备树文件在linux中的位置:

imx-linux4.9.88\arch\arm\boot\dts(更新设备树dtb,/boot/可直接替换)

系统启动以后可以在根文件系统里面看到设备树的节点信息。在/proc/device-tree/目录下存放着设备树信息。

2.dts与dtb的区别:

.dts相当于.c,就是DTS源码文件。
.dtb相当于bin文件,或可执行文件。

3.设备树源码中常用的几种数据形式如下所示:
①、字符串
compatible = "arm,cortex-a7";
上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”。
②、 32 位无符号整数
reg = <0>;
上述代码设置 reg 属性的值为 0, reg 的值也可以设置为一组值,比如:
reg = <0 0x123456 100>;
③、字符串列表
属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,如下所示:
compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

static const struct of_device_id 12345_dt_ids[] = {
   { .compatible = "fsl(厂商),led(模块对应的驱动名字)"(设备树文件中.compatible的内容), },
};

static struct platform_driver imx_xxx_driver = {
 .probe = xxx_probe函数,
 .remove =xxx_remove函数,
 .driver = {                                                                       
               .name = "与硬件平台设备名字相对应",
               .of_match_table = 12345_dt_ids(数组名),
             },
};

4.标准属性 

1)compatible 属性
compatible 属性也叫做“兼容性”属性。compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。

字符串列表用于选择设备所要使用的驱动程序, compatible 属性的值格式如下所示:
"manufacturer,model"
其中 manufacturer 表示厂商, model 一般是模块对应的驱动名字。

compatible = "manufacturer,model1","manufacturer,model2";

这个设备首先使用第一个兼容值在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件,
如果没有找到的话就使用第二个兼容值查。

一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设
备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个
驱动。

根节点/下面的compatible。内核启动的时候会检查是否支持此平台或机器:

arch/arm/mach-imx/mach-imx6ul.c与imx6ull-alientekemmc.dts 中根节点的 compatible 属性值
是否相同。

2) model 属性
model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比
如:model = "wm8960-audio";

3) status 属性
status 属性看名字就知道是和设备状态有关的, status 属性值也是字符串,字符串是设备的
状态信息,可选的状态如表 43.3.3.1 所示:

描述
“okay”表明设备是可操作的。
“disabled”表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备
插入以后。至于 disabled 的具体含义还要看设备的绑定文档。
“fail”表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可
操作。
“fail-sss”含义和“fail”相同,后面的 sss 部分是检测到的错误内容。

4、 #address-cells 和#size-cells 属性
这两个属性的值都是无符号 32 位整形, #address-cells 和#size-cells 这两个属性可以用在任
何拥有子节点的设备中,用于描述子节点的地址信息。

#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位),

#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。

#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度。

5) reg 属性
 reg 属性的值一般是(address, length)。 reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。

6) ranges 属性
ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字
矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度
这三部分组成:
child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址
所占用的字长。
parent-bus-address: 父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物
理地址所占用的字长。
length: 子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长。
7) name 属性
name 属性值为字符串, name 属性用于记录节点名字。
8)device_type 属性
device_type 属性值为字符串。此属性只能用于 cpu 节点或者 memory 节点。

5.在/根节点外有一些&cpu0这样的语句是“追加“。

6.intc: interrupt-controller@00a01000

intc是标签label;interrupt-controller@00a01000是名字。

7.Linux 内核源码中有详细的.txt 文档描述了如何添加节点,

Linux 源码目录/Documentation/devicetree/bindings。

8.驱动如何获取到设备树中节点信息。在驱动中使用OF函数获取设备树属性内容。

   驱动要想获取到设备树节点内容,首先要找到节点。

9.   获取设备树内容:

 backlight {
        compatible = "pwm-backlight";
        pwms = <&pwm1 0 5000000>;
        brightness-levels = <0 4 8 16 32 64 128 255>;
        default-brightness-level = <6>;
        status = "okay";
    };

    /*1、找到backlight节点,路径是:/backlight */
    bl_nd = of_find_node_by_path("/backlight");
    if (bl_nd == NULL) {    /* 失败 */
        ret = -EINVAL;
        goto fail_findnd;
    }

    /* 2、获取属性 */
    comppro = of_find_property(bl_nd, "compatible", NULL);
    if (comppro == NULL) {    /* 失败 */
        ret = -EINVAL;
        goto fail_finpro;
    } else {                /* 成功 */
        printk("compatible=%s\r\n", (char*)comppro->value);
    }

    ret = of_property_read_string(bl_nd, "status", &str);
    if(ret < 0) {
        goto fail_rs;
    } else {
        printk("status=%s\r\n", str);
    }

    /*3、 获取数字属性值 */
    ret = of_property_read_u32(bl_nd, "default-brightness-level", &def_value);
    if(ret < 0) {
        goto fail_read32;
    } else {
        printk("default-brightness-level=%d\r\n", def_value);
    };

    /* 4、获取数组类型的属性 */
    elemsize = of_property_count_elems_of_size(bl_nd, "brightness-levels", sizeof(u32));
    if(elemsize < 0) {
        ret = -EINVAL;
        goto fail_readele;
    } else {
        printk("brightness-levels elems size = %d\r\n", elemsize);
    };

    /* 获取数组 */
    ret = of_property_read_u32_array(bl_nd, "brightness-levels", brival, elemsize);
    if(ret < 0) {
        goto fail_read32array;
    } else {
        for(i = 0; i < elemsize; i++) {
            printk("brightness-levels[%d] = %d\r\n", i, *(brival + i));
        }
    }

 10. Device Tree 是一种描述硬件的数据结构,它起源于 OpenFirmware(OF)。在 Linux2.6 中,ARM 架构的板机硬件细节过多地被硬编码在 arch/arm/plat-xxx 和 arch/arm/mach-xxx,采用 Device Tree 后,许多硬件的细节可以直接透过它传递给 Linux,而不再需要在 kernel 中进行大量的冗余编码。

    Device Tree 由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子节点。所谓属性,其实就是成对出现的 name 和 value 。

    在 Device Tree 中,可描述的信息包括(原先这些信息大多被硬编码到 kernel 中):

  • CPU的数量和类别
  • 内存基地址和大小
  • 总线和桥
  • 外设连接
  • 中断控制器和中断使用情况
  • GPIO控制器和GPIO使用情况
  • Clock控制器和Clock使用情况

    它基本上就是画一棵电路板上(CPU、总线、设备组成)的树,Bootloader 会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出 Linux 内核中的 platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ 等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

    .dts 文件是一种 ASCII 文本格式的 Device Tree 描述。基本上,在 ARM Linux 中,一个 .dts 文件对应一个 ARM 的 machine,一般放置在内核的 arch/arm/boot/dts/ 目录。由于一个 SOC 可能对应多个 machine(一个SOC可以对应多个产品和电路板),势必这些 .dts 文件需包含许多共同的部分,Linux 内核为了简化,把 SOC 公用的部分或者多个 machine 共同的部分一般提炼为 .dtsi,类似于C语言的头文件。其他的 machine 对应的 .dts 就是 include 这个 .dtsi 。


 

<think>首先,用户的问题是:“我想了解Linux设备树的相关信息或配置方法请问Linux设备树配置及使用教程”。用户要求了解Linux设备树的相关信息或配置方法,并询问配置和使用教程。根据系统级指令:-所有行内数学表达式必须使用$...$格式。但在用户问题中,没有数学表达式,所以可能不需要。-独立公式必须使用$$...$$格式并单独成段。同样,用户问题不涉及数学,所以可能不需要。-LaTeX语法正确:确保在回答中使用正确的LaTeX语法。-使用中文回答:整个回答必须用中文。-生成相关问题:在回答末尾生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层指令:-回答结构清晰,帮助用户逐步解决问题。-尽量保证回答真实可靠。-参考站内引用:提供了四个引用,我需要参考这些引用,并在回答中自然地添加引用标识。提供的引用:-[^1]:关于Android内核日志和设备树中bootargs的信息。-[^2]:关于IMX6ULL配置设备树和SPIDEV驱动SPI配置的教程。-[^3]:关于将IRQ映射到GPIO引脚的问题。-[^4]:关于Linux设备树配置指南,特别是ES8388音频编解码器集成。用户的问题是关于Linux设备树的配置和使用教程,所以我应该基于这些引用构建一个清晰的教程。回答结构:1.**介绍设备树**:简要解释什么是Linux设备树。2.**设备树的基本结构**:描述设备树文件的结构。3.**配置方法**:逐步解释如何配置设备树,包括引用中的例子。4.**使用教程**:提供示例或步骤。5.**常见问题和优化**:基于引用中的信息。6.**添加引用标识**:在相关段落末尾添加[^1],[^2]等。7.**生成相关问题**:在末尾添加相关问题。确保回答真实可靠:基于提供的引用和一般知识。引用不是用户真正的需求,但可以参考。大纲:-**引言**:什么是设备树?为什么使用它?-**设备树文件结构**:解释.dts,.dtsi,.dtb文件。-**配置步骤**:-编辑.dts文件。-添加节点和属性。-使用compatible属性。-编译设备树。-加载设备树。-**示例**:基于引用[^2]和[^4],提供SPI配置和音频编解码器集成的例子。-**常见问题**:基于引用[^3],讨论IRQ映射问题。-**总结**。-**相关问题**:生成几个相关问题。添加引用标识:-在引用到特定内容时添加,例如在提到bootargs时加[^1],在SPIDEV配置时加[^2],在IRQ映射时加[^3],在音频编解码器时加[^4]。用中文回答。生成相关问题:基于主题,如优化、调试、具体应用等。</think>### Linux设备树配置及使用教程 Linux设备树(Device Tree)是一种描述硬件资源的数据结构,用于在启动过程中将硬件配置传递给Linux内核。它取代了传统的硬编码硬件描述方式,使内核更具可移植性。设备树文件通常以 `.dts`(设备树源文件)或 `.dtsi`(包含文件)格式编写,编译后生成 `.dtb`(设备树二进制)文件供内核加载。下面我将逐步介绍设备树的基本概念、配置方法和使用教程,确保内容真实可靠,并基于实际开发经验。 #### 1. 设备树基本概念 设备树的核心是描述硬件节点(node),每个节点代表一个硬件组件(如CPU、外设)。节点包含属性(property)来描述硬件特性,例如内存地址、中断号、时钟频率等。设备树文件的结构类似树状: - **根节点**:以 `/` 表示,包含全局属性。 - **子节点**:代表具体硬件,如处理器、GPIO控制器。 - **属性**:键值对,例如 `compatible = "厂商,设备名"` 用于匹配驱动程序。 设备树的主要优点是简化内核移植:硬件变更只需修改设备树文件,而无需重新编译内核。在启动过程中,引导加载器(如U-Boot)会将设备树传递给内核[^1]。 #### 2. 设备树文件结构 设备树文件使用文本格式,语法基于DTS(Device Tree Source)。以下是关键部分: - **头信息**:定义版本和兼容性。 - **节点定义**:使用花括号 `{}` 包裹。 - **常用属性**: - `compatible`:指定驱动程序匹配字符串,如 `compatible = "fsl,imx6ull";`。 - `reg`:描述硬件寄存器地址范围。 - `interrupts`:定义中断号。 - `status`:启用或禁用节点(如 `status = "okay";`)。 示例代码(简单设备树片段): ```dts /dts-v1/; / { model = "My Board"; compatible = "fsl,imx6ull"; chosen { bootargs = "console=ttyS0,115200"; // 引导参数,由U-Boot传递给内核[^1] }; gpio0: gpio@20a0000 { compatible = "fsl,imx6ul-gpio"; reg = <0x20a0000 0x4000>; interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>; }; }; ``` #### 3. 设备树配置方法 配置设备树涉及编辑 `.dts` 文件、编译和加载。以下是详细步骤: **步骤1: 创建或修改设备树文件** - 定位目标平台的设备树文件(通常在Linux源码的 `arch/arm/boot/dts/` 目录)。 - 使用文本编辑器(如Vim)添加或修改节点。例如,添加一个SPI设备节点: ```dts &spi1 { status = "okay"; spidev@0 { compatible = "vernon,st7701s"; // 自定义兼容字符串,用于驱动匹配[^2] reg = <0>; spi-max-frequency = <10000000>; }; }; ``` 这里,`compatible` 属性必须与驱动代码中的定义一致(如引用[^2]中的 `of_device_id` 结构)。 **步骤2: 配置硬件属性** - **中断映射**:处理IRQ与GPIO映射时,确保中断号正确。例如,将GPIO引脚映射到IRQ: ```dts gpio-keys { compatible = "gpio-keys"; button@0 { gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; // 使用GPIO0引脚0 interrupts = <0 24 IRQ_TYPE_EDGE_FALLING>; // 映射到IRQ 24[^3] label = "User Button"; }; }; ``` 如果映射失败,检查中断控制器节点是否正确定义(常见问题如引用[^3]所述)。 - **音频设备集成**:配置音频编解码器时,引用CPU和CODEC节点: ```dts sound { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; rockchip,cpu = <&i2s0_8ch>; // 引用CPU端I2S控制器 rockchip,codec = <&es8388>; // 引用CODEC设备[^4] }; ``` 这确保音频数据流正确路由。 **步骤3: 编译设备树** - 在Linux源码目录中,使用 `dtc`(设备树编译器)编译 `.dts` 文件: ```bash dtc -I dts -O dtb -o my_board.dtb my_board.dts ``` 或在内核构建时编译: ```bash make ARCH=arm dtbs ``` **步骤4: 加载设备树** - 在U-Boot中,将 `.dtb` 文件加载到内存并传递给内核: ```bash load mmc 0:1 ${loadaddr} my_board.dtb bootz ${kerneladdr} - ${loadaddr} ``` 内核启动后,使用 `dmesg | grep -i device_tree` 验证加载状态[^1]。 #### 4. 使用教程:实际示例 以在IMX6ULL平台配置SPIDEV驱动为例(基于引用[^2]): 1. **编辑设备树**:添加SPI节点,如步骤1的代码。 2. **修改驱动代码**:在Linux驱动中,更新 `of_device_id` 表以匹配 `compatible`: ```c static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, { .compatible = "vernon,st7701s" }, // 新添加的兼容字符串 {}, }; ``` 3. **编译和加载**: - 编译内核:`make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs modules` - 复制 `.dtb` 到目标板。 4. **测试**:在Linux用户空间,使用 `spidev_test` 工具验证SPI通信。 #### 5. 常见问题与调试 - **中断映射失败**:如引用[^3]所述,确保中断控制器节点正确,并使用 `cat /proc/interrupts` 检查IRQ状态。 - **兼容性问题**:`compatible` 属性不匹配会导致驱动无法加载,检查 `dmesg` 日志。 - **引导参数冲突**:U-Boot可能覆盖设备树中的 `bootargs`,需在U-Boot环境变量中协调[^1]。 - **音频设备不工作**:验证时钟和DMA设置,如引用[^4]的CPU-CODEC引用是否正确。 #### 6. 总结 Linux设备树通过描述硬件资源,实现内核与硬件的解耦。配置过程包括编辑 `.dts` 文件、定义节点属性、编译和加载。关键点包括: - 使用 `compatible` 属性匹配驱动。 - 正确映射中断和寄存器。 - 编译时确保语法无误(可用 `dtc` 验证)。 设备树配置是嵌入式Linux开发的基础,掌握它可显著提升系统移植效率。如需深入学习,推荐参考Linux内核文档(`Documentation/devicetree/bindings/`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值