首页 > 系统相关 >linux设备树-基础介绍

linux设备树-基础介绍

时间:2023-03-30 23:11:15浏览次数:49  
标签:中断 cells linux 介绍 address 属性 节点 设备

一、介绍

1.1 为什么引入设备树

我们首先回顾一下我们之前学习过的驱动程序。比如:

linux驱动移植-lcd驱动基础;在arch/arm/plat-samsung/devs.c文件中定义了platform设备s3c_device_lcd,在arch/arm/mach-s3c24xx/mach-smdk2440.c文件定义了platform数据smdk2440_fb_info。

linux驱动移植-linux块设备驱动Nand Flash;在arch/arm/plat-samsung/devs.c文件中定义了platform设备s3c_device_nand ,在 arch/arm/mach-s3c24xx/common-smdk.c文件定义了platform数据smdk_nand_info。

linux驱动移植-linux块设备驱动Nand Flash;在arch/arm/plat-samsung/devs.c文件中定义了platform设备s3c_device_nand ,在 arch/arm/mach-s3c24xx/common-smdk.c文件定义了platform数据smdk_nand_info。

linux驱动移植-linux块设备驱动Nor Flash;在drivers/mtd/maps/physmap-core.c文件中定义了platform设备physmap_flash,同时在文件内定义了platform数据physmap_flash_data。

linux驱动移植-DM9000网卡驱动;在arch/arm/mach-s3c24xx/mach-smdk2440.c文件中定义了platform设备smdk2440_device_eth,同时在文件内定义了platform数据smdk2440_dm9k_pdata 。

linux驱动移植-I2C适配器驱动移植;在arch/arm/mach-s3c24xx/mach-smdk2440.c文件中定义了platform设备s3c_device_i2c0,同时在文件内定义了platform数据default_i2c_data 。

linux驱动移植-I2C设备驱动移植(AT24C08);在arch/arm/mach-s3c24xx/mach-smdk2440.c文件中定义了I2C从设备信息i2c_board_info 。

linux驱动移植-SPI控制器驱动;在arch/arm/plat-samsung/devs.c文件中定义了platform设备s3c_device_spi1,同时在arch/arm/mach-s3c24xx/mach-smdk2440.c文件内定义了platform数据s3c2440_spi1_data 。

linux驱动移植-SPI驱动移植(OLED SSD1306);在arch/arm/mach-s3c24xx/mach-smdk2440.c文件中定义了SPI从设备信息spi_board_info 。

linux驱动移植-UART设备驱动;在arch/arm/plat-samsung/init.c文件中定义了platform设备s3c24xx_uart_device0,同时在该文件内定义了platform数据uart_cfgs。

linux驱动移植-RTC驱动;在arch/arm/plat-samsung/devs.c文件中定义了platform设备s3c_device_rtc ,同时在drivers/rtc/rtc-s3c.c文件内定义了设置platform数据类型为s3c_rtc 。

在之前我们介绍的驱动程序中,Mini2440开发板板极硬件资源都是被硬编码在arch/arm/plat-samsung/devs.c和arch/arm/mach-s3c24xx/mach-smdk2440.c文件,比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码基本都是和开发外围设备相关的,开发板不同这些信息也会因此不同,与之而来就带来了诸多问题。

比如ARM的merge工作量较大,随着着芯片的发展,linux内核中就包含着越来越多这些描述设备的代码,导致Linux内核代码会很臃肿。为此linux还对ARM平台相关代码做出了相关的规范调整:

  • ARM的核心代码保存在arch/arm目录下;
  • ARM SoC core architecture code保存在arch/arm目录下;
  • ARM SoC的周边外设模块的驱动保存在drivers目录下;
  • ARM SoC的特定machine代码在arch/arm/mach-xxx目录下;
  • ARM SoC board specific的代码(arch/arm/plat-xxx)被移除,由Device Tree机制来负责传递硬件拓扑和硬件资源信息;硬件的细节可以直接通过Device Tree传递给linux驱动程序,而不再需要在kernel中进行大量的冗余编码。

1.2 设备树(Device Tree)

linux内核从3.x开始引入设备树的概念,用于将设备信息与驱动代码分离开来。在设备树出现之前,所有关于设备的硬件信息都要编写在驱动程序里,一旦外围设备变化,驱动代码就要重写。

引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。

比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的"arch/arm/boot/dts/"目录内,比如firefly  rk3288参考板的板级设备树文件就是"arch/arm/boot/dts/rk3288-firefly.dts"。这个文件可以通过$make dtbs命令编译成二进制的.dtb文件供内核驱动使用。

基于同样的软件分层设计的思想,由于一个SoC可能对应多个machine,如果每个machine的设备树都写成一个完全独立的.dts文件,那么势必相当一些.dts文件有重复的部分,为了解决这个问题,Linux设备树目录把一个SoC公用的部分或者多个machine共同的部分提炼为相应的.dtsi文件。这样每个.dts就只有自己差异的部分,公有的部分只需要"include"相应的.dtsi文件, 这样就是整个设备树的管理更加有序。

一般.dtsi文件一般是芯片外设的一些信息,比如CPU架构、主频、外设寄存器地址范围,比如UART、IIC等等。这些信息一般是不能修改的,而我们的板载外设信息一般放在dts文件中,使我们根据我们板子的外设自己添加的,是可以修改的。

1.3 设备树文件

设备树源文件格式支持dts、dtsi:

  • dts:硬件的相关信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一份xxxx.dts,一般在linux源码中存在大量的dts文件,对于arm架构可以在arch/arm/boot/dts找到相应的dts,一个dts文件对应一个ARM的machie。
  • dtsi:对于一些相同的dts配置可以抽象到dtsi文件中,然后类似于C语言的方式可以include到dts文件中,对于同一个节点的设置情况,dts中的配置会覆盖dtsi中的配置;

这些源文件同我们的C代码一样,并不能直接使用的,而是得经过一个编译过程生成机器可运行的二进制文件:

  • dtb:dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过bootloader引导程序加载到内核。所以bootloader需要支持设备树才行;linux kernel也需要加入设备树的支持;

dts文件使用工具dtc进行编译,可以在ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具。

uboot从v1.1.3开始支持设备树,其对ARM的支持则是和ARM内核支持设备树同期完成。

为了使能设备树,需要在编译uboot的时候在config文件中加入:

#define CONfiG_OF_LIBFDT·

在uboot中,可以从NAND、SD或者TFTP等任意介质中将.dtb读入内存,假设.dtb放入的内存地址为0x71000000,之后可在uboot中运行fdt addr命令设置.dtb的地址,如:

fdt addr 0x71000000·

fdt的其他命令就变得可以使用,如fdt resize、fdt print等。
然后通过以下命令来启动内核:

bootz kernel_addr initrd_address dtb_address

其中:

  • 第一个参数为内核映像的地址;
  • 第二个参数为initrd的地址,若不存在initrd,可以用“-”符号代替;
  • 第三个参数dtb_address为.dtb文件在内存的地址

二、设备树结构

设备树源文件也是需要根据一定规则来编写的,同C语言一样,也要遵循一些语法规则。

设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点;下面是一个典型的设备树结构:

/dts-v1/;      /* 版本 */
#include <dt-bindings/input/input.h> /* 包含c头文件 */
#include "xxx.dtsi" /* 包含设备树头文件 */ / { /* 根节点 */ node1 { a-string-property = "A string"; a-string-list-property = "first string", "second string"; // hex is implied in byte arrays. no '0x' prefix is required a-byte-data-property = [01 23 34 56]; child-node1 { first-child-property; second-child-property = <1>; a-string-property = "Hello, world"; }; child-node2 { }; }; node2 { an-empty-property; a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */ child-node1 { }; }; };

设备树文件具有以下几种特性:

  • 每个设备树文件都有一个根节点,除了根节点,每个节点都只有一个父节点;
  • 每个节点用节点名字标识,节点名字的格式是node-name@unit-address;如果该节点没有reg属性,那么该节点名字中必须不能包括@和unit-address;
  • 根节点的名字是确定的,必须是"/";
  • 每个节点都包含了若干个key-value对(属性)来描述该节点的一些特性,每个属性的描述用;结束;

在dts文件中,一个节点被定义成:

[label:] node-name[@unit-address] {
   [properties definitions]
   [child nodes]
} 

上图中:

  • []:表示该项可以省略;
  • label:标签,方便在dts文件中引用;
  • node-name:节点名;
  • unit-address:地址;
  • properties:属性定义;
  • child nodes:子节点;

2.1 标签

在设备树中,如果我们想引用一个节点,必须要使用全路径,比如/node-name-1/node-name-2/node-name-N,这样当一个节点嵌套比较深的时候就不是很方便。

所以,设备树允许我们为一个节点起一个别名,也就是标签,借以省去冗长的路径。这样就可以实现类似函数调用的效果。

编译设备树的时候,相同的节点的不同属性信息都会被合,相同节点的相同的属性会被重写,使用引用可以避免移植者四处找节点,直接在板级.dts增改即可。

下面的例子中就是直接引用了dtsi中的节点cpu0,并向其中添加/修改新的属性信息:

&cpu0 {
        cpu0-supply = <&vdd_cpu>;
};

2.2 node-name[@unit-address]

linux内核约定节点名应写成形如node-name[@unit_address]的形式,其中:

  • node-name是节点名字,为ASCII字符串,最长可以是31个字符长度;节点名字应该能够清晰的描述出节点的功能,比如uart0就表示这个节点是UART0外设;
  • unit_address一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话unit-address可以不要,比如cpu@0、interrupt-controller@00a01000;

下面就是典型节点的写法,该节点用于描述rtc设备硬件信息:

 rtc@57000000 {
       compatible = "samsung,s3c2410-rtc";
       reg = <0x57000000 0x100>;
       interrupts = <0 0 30 3>, <0 0 8 3>;
       status = "disabled";
};

linux中的设备树还包括一些特殊的节点,比如chosen,aliases等。

2.2.1 choosen节点

chosen 并不是一个真实的设备,chosen节点主要目的就是将uboot里面bootargs环境变量值传递给linux内核作为命令行参数,比如:

chosen {   
    bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";   
};
2.2.2 aliases节点

aliases节点为了解决节点路径名过长的问题,引入了节点别名的概念,可以引用到一个全路径的节点。

aliases {
         pinctrl0 = &pinctrl_0;
         serial0 = &uart0;
         serial1 = &uart1;
         serial2 = &uart2;
};
2.2.3 CPU节点

cpus节点下有1个或多个cpu子节点,,cpu子节点中用reg属性用来标明自己是哪一个cpu:

        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                enable-method = "rockchip,rk3066-smp";
                rockchip,pmu = <&pmu>;

                cpu0: cpu@500 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a12";
                        reg = <0x500>;
                        resets = <&cru SRST_CORE0>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
                        dynamic-power-coefficient = <370>;
                };
                cpu1: cpu@501 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a12";
                        reg = <0x501>;
                        resets = <&cru SRST_CORE1>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
                        dynamic-power-coefficient = <370>;
                };
                cpu2: cpu@502 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a12";
                        reg = <0x502>;
                        resets = <&cru SRST_CORE2>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
                        dynamic-power-coefficient = <370>;
                };
                cpu3: cpu@503 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a12";
                        reg = <0x503>;
                        resets = <&cru SRST_CORE3>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
                        dynamic-power-coefficient = <370>;
                };
        };
2.2.4 memory节点

所有设备树都需要一个memory设备节点,它描述了系统的物理内存布局。如果系统有多个内存块,可以创建多个memory节点,或者可以在单个memory节点的reg属性中指定这些地址范围和内存空间大小。

例如:一个64位的系统有两块内存空间:

  • RAM1:起始地址是0x0,地址空间是大小0x08000000;
  • RAM2:起始地址是0x10000000,地址空间大小也是0x08000000;

同时根节点下的 #address-cells = <2>和#size-cells = <2>,这个memory节点描述为:

memory@0 {
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x08000000>;
};
memory@10000000 {
    device_type = "memory";
    reg = <0x00000000 0x10000000 0x00000000 0x08000000>;
};

2.3 key

在设备树中,键值对是描述属性的方式,比如linux驱动中可以通过设备节点中的"compatible"这个属性查找设备节点。
linux设备树语法中定义了一些具有规范意义的属性,包括:compatible, address, interrupts等,这些信息能够在内核初始化找到节点的时候,自动解析生成相应的设备信息。

此外,还有一些Linux内核定义好的,一类设备通用的有默认意义的属性,这些属性一般不能被内核自动解析生成相应的设备信息,但是内核已经编写的相应的解析提取函数,常见的有 "mac_addr","gpio","clock","power"。"regulator" 等等。

2.3.1 compatible

compatible属性也叫做兼容性属性,这是非常重要的一个属性。compatible属性的值是一个字符串列表,compatible属性用于将设备和驱动绑定起来。compatible属性的值格式如下所示:

"manufacturer,model"

其中:

  • manufacturer:表示厂商;
  • model:一般是模块对应的驱动名字。

比如S3C2440 RTC驱动和设备节点就是通过"compatible"进行匹配,arch/arm/boot/dts/s3c24xx.dtsi中定义有设备节点:

 rtc@57000000 {
       compatible = "samsung,s3c2410-rtc";  /* 支持字符串数组 */
       reg = <0x57000000 0x100>;
       interrupts = <0 0 30 3>, <0 0 8 3>;
       status = "disabled";
};

然后我们在内核源码中找到RTC驱动定义,在drivers/rtc/rtc-s3c.c文件,可以发现这个驱动使用了设备树描述的设备信息,我们可以找到它用来描述设备信息的结构体。
可以看出,驱动中用于匹配的结构使用的compatible和设备树中一模一样,否则就可能无法匹配,这里另外的一点是struct of_device_id数组的最后一个成员一定是空,因为相关的操作API会读取这个数组直到遇到一个空。

static const struct of_device_id s3c_rtc_dt_match[] = {  // 存储设备驱动程序和设备节点之间得匹配信息
        {
                .compatible = "samsung,s3c2410-rtc",
                .data = &s3c2410_rtc_data,
        },
        ......
        { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);

static struct platform_driver s3c_rtc_driver = {
        .probe          = s3c_rtc_probe,     // rtc探测函数
        .remove         = s3c_rtc_remove,    // rtc移除函数  
        .driver         = {
                .name   = "s3c-rtc",
                .pm     = &s3c_rtc_pm_ops,
                .of_match_table = of_match_ptr(s3c_rtc_dt_match),
        },
};
2.3.2 address 

几乎所有的设备都需要与CPU的IO口相连,所以其IO端口信息就需要在设备节点节点中说明。常用的属性有:

  • #address-cells:用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量;也就是说需要用多少个u32位数来描述该地址;
  • #size-cells:用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量;也就是说需要用多少个u32的位数来描述地址长度;

有了这两个属性,子节点中的"reg"就可以描述一块连续的地址区域。

下例中,父节点中指定了#address-cells = <1>; #size-cells = <1>,则子节点i2c@54000000中的reg中:

  • 使用1个u32数来表示地址,,即0x54000000,也就是I2C寄存器寄基地址;
  • 使用1个u32数来表示地址跨度,即是0x100:
/ {
    #address-cells = <1>;
    #size-cells = <1>;
    i2c@54000000 {
                compatible = "samsung,s3c2410-i2c";
                reg = <0x54000000 0x100>;
                interrupts = <0 0 27 3>;
                #address-cells = <1>;
                #size-cells = <0>;
                status = "disabled";
        };

    };
};
2.3.3 interrupts

一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有:interrupt-controller、#interrupt-cells、interrupt-parent、interrupts。

interrupt-controller表示这个节点是一个中断控制器,需要注意的是,一个SoC中可能有不止一个中断控制器,下面是在文件"arch/arm/boot/dts/s3c24xx.dtsi"中对S3C2440的中断控制器节点描述:

intc:interrupt-controller@4a000000 {
     compatible = "samsung,s3c2410-irq";
     reg = <0x4a000000 0x100>;
     interrupt-controller;
     #interrupt-cells = <4>;
};

#interrupt-cells是中断控制器节点的属性,用来描述子节点中"interrupts"属性使用了几个cell才能确定所使用的中断。以S3C2440位列,该属性的值是4,则子节点的interrupts一个cell的4个32bits整数值分别为:

  • 第0位:中断控制器编号:0表示主中断源、1表示带有子中断的内部中断、2表示外部中断(也是子中断);
  • 第1位:表示子中断所属的主中断的硬件中断号:对于子中断,这个参数才有意义;
  • 第2位:硬件中断编号:表示位于当前中断控制器中的中断号,比如中断控制器编号为0时,对应的硬件中断编号为0~31;中断控制器编号为1时,对应的硬件中断编号为0~14;中断控制器编号为2时,对应的硬件中断编号为0~23;
  • 第3位:中断类型:1为上升沿触发、2位下降沿触发、3位双边沿触发、4位高电平触发、8位低电平触发、12位高低电平触发;

注意:S3C2440物理只有一个中断控制器,软件层面上抽象出来3个中断控制器,具体参考linux驱动移植-中断子系统执行流程

  • 一个根中断控制器管理主中断源;
  • 两个子中断控制器,一个用于管理外部中断源、另一个管理带有子中断的内部中断源;

示例:

        uart0: serial@50000000 {
                compatible = "samsung,s3c2410-uart";
                reg = <0x50000000 0x4000>;
                interrupts = <1 28 0 4>, <1 28 1 4>;
                status = "disabled";
        };

这里配置的interrupts描述了串口0的收发中断:

  • <1 28 0 4>:描述的是带有子中断内部中断,串口0主中断硬件中断号为28,串口0接收硬件中断编号为0,高定平触发;
    • 串口0主中断硬件编号28,对应的软件中断号位为 44,即IRQ_UART0;
    • 串口0接收硬件中断编号为0,对应的软件中断号位为74,即IRQ_S3CUART_RX0;
  • <1 28 1 4>:描述的是带有子中断内部中断,串口0主中断硬件中断号为28,串口0发送硬件中断编号为1,高定平触发;
    • 串口0主中断硬件编号28,对应的软件中断号位为 44,即IRQ_UART0;
    • 串口0发送硬件中断编号为0,对应的软件中断号位为75,即IRQ_S3CUART_TX0;

interrupt-parent:标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的;

/ {
        compatible = "samsung,s3c24xx";
        interrupt-parent = <&intc>;
        intc:interrupt-controller@4a000000 {
                compatible = "samsung,s3c2410-irq";
                reg = <0x4a000000 0x100>;
                interrupt-controller;
                #interrupt-cells = <4>;
        };

        ...
 }
2.3.4 reg

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

reg属性的值,是一系列的“address size”,用多少个32位的数来表示address和size,由其父节点的#address-cells、#size-cells决定。示例:

/ {
         #address-cells = <1>;
          #size-cells = <1>;
          timer@51000000 {
                compatible = "samsung,s3c2410-pwm";
                reg = <0x51000000 0x1000>;
                interrupts = <0 0 10 3>, <0 0 11 3>, <0 0 12 3>, <0 0 13 3>, <0 0 14 3>;
                #pwm-cells = <4>;
        };

};

上图描述了节点timer@51000000,timer节点描述了S3C2440的timer相关信息,重点是reg属性。

其中timer的父节点设置了#address-cells = <1>、#size-cells = <1>,因此reg属性中address=0x51000000,length=0x100。查阅S3C2440 datasheet可知,S3C2440的定时器寄存器首地址为0x51000000,但是定时器的地址长度(范围)并没有0x100这么多,这里我们重点是获取定时器寄存器首地址。

2.3.5 status

status标识了设备的状态,使用status可以去禁止设备或者启用设备,看下设备树规范中的status可选值:

  • okay :表示设备正在运行;
  • disabled :表示该设备目前尚未运行,但将来可能会运行;
  • fail :表示设备无法运行。 在设备中检测到严重错误,确实如此没有修理就不可能投入运营;
  • fail-sss:表示设备无法运行。 在设备中检测到严重错误,它是没有修理就不可能投入运营。 值的sss部分特定于设备并指示检测到的错误情况;
2.3.6 model

model属性值是一个字符串,一般model属性描述设备模块信息,比如名字什么的,比如:

model = "wm8960-audio";
2.3.7 name

name属性值为字符串, name属性用于记录节点名字, name属性已经被弃用,不推荐使用name属性,一些老的设备树文件可能会使用此属性。

2.3.8 device_type

device_type属性值为字符串, IEEE 1275会用到此属性,用于描述设备的 FCode,但是设备树没有 FCode,所以此属性也被抛弃了。此属性只能用于cpu节点或者memory节点。

memory@30000000 {
    device_type = "memory";
    reg =  <0x30000000 0x4000000>;
};
2.3.9 ranges

ranges属性值可以为空或者按照“child-bus-address,parent-bus-address,length”格式编写的数字矩阵,ranges是一个地址映射/转换表,ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:

  • child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells确定此物理地址所占用的字长;
  • parent-bus-address :父总线地址空间的物理地址,同样由父节点的#address-cells确定此物理地址所占用的字长;
  • length:子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长;

示例:

soc {
    compatible = "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    ranges = <0x0 0xe0000000 0x00100000>;
    serial {
        device_type = "serial";
        compatible = "ns16550";
        reg = <0x4600 0x100>;
        clock-frequency = <0>;
        interrupts = <0xA 0x8>;
        interrupt-parent = <&ipic>;
        };
};

节点soc定义的ranges属性,值为 <0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000) 的地址范围,子地址空间的物理起始地址为0x0,父地址空间的物理起始地址为 0xe0000000。

serial是串口设备节点,reg属性定义了serial设备寄存器的起始地址为0x4600,寄存器长度为0x100。经过地址转换, serial设备可以从0xe0004600开始进行读写操作,0xe0004600 = 0x4600 + 0xe0000000。

2.4 节点值

节点属性(property)值标识了设备的特性,它的值(value)是多种多样的。

2.4.1 空

可能是空,也就是没有值的定义,如下:

interrupt-controller;
2.4.2 字符串

可能为字符串,如下

compatible = "samsung,s3c24xx";

也可以为字符串数组,如下:

compatible = "firefly,firefly-rk3288", "rockchip,rk3288";
2.4.3 u32、u64数值

可能是一个u32数值,一个32位的数据,用尖括号包围起来,如:

#interrupt-cells = <4>;

一个64位数据(使用2个32位数据表示),用尖括号包围起来,如:

clock-frequency = <0x00000001 0x00000000>;

也可以是一个数值数组,如下:

interrupts = <0 0 0 3>,<0 0 1 3>,<0 0 2 3>,<0 0 3 3>,<0 0 4 4>,<0 0 5 4>;
2.4.4 16进制字节序列

字节序列,用中括号包围起来,如:

local-mac-address = [000 00 de ad be ef]

参考文章

[1]linux设备驱动(17)设备树详解1-概论

[2]Linux设备树语法详解

[3]Linux设备树详解(一) 基础知识

[4]linux设备驱动(18)设备树详解2-基础知识

[5]【正点原子I.MX6U-MINI驱动篇】4、Linux设备树详解

[6]一文搞定 Linux 设备树

标签:中断,cells,linux,介绍,address,属性,节点,设备
From: https://www.cnblogs.com/zyly/p/17266960.html

相关文章

  • Linux 用户和用户组管理
    Linux用户和用户组管理Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪,并控制他们对系统资源的访问;另一方面也可以帮助......
  • 四个常见的Linux面试问题。
    刚毕业要找工作了,只要是你找工作就会有面试这个环节,那么在面试环节中,有哪些注意事项值得我的关注呢?特别是专业技术岗位,这样的岗位询问一般都是在职的工程师,如何在面试环节更好地理解面试官的问题,我们一起往下看吧。在学校学习也好,在培训机构或者网络在线学习也好,无论是通过那种途径......
  • 四个常见的Linux面试问题。
    刚毕业要找工作了,只要是你找工作就会有面试这个环节,那么在面试环节中,有哪些注意事项值得我的关注呢?特别是专业技术岗位,这样的岗位询问一般都是在职的工程师,如何在面试环节更好地理解面试官的问题,我们一起往下看吧。在学校学习也好,在培训机构或者网络在线学习也好,无论是通过那种途径......
  • 又一款眼前一亮的Linux终端工具!
    大家好,我是良许。最近二舅视频刷爆了全网,大家有没去看呢?强烈推荐大家观看一波,也就11分钟,保证会触动你的泪点。不过今天不讲二舅哈,还是来聊聊技术。今天给大家介绍一款最近发现的功能十分强大,颜值非常高的一款终端工具。这个神器我是在其他公众号文章上看到的,但他们都没把它的......
  • 飞腾杯-----linux系统下U盘的挂载
    U盘识别把U盘插到飞腾教育开发版的USB口上。输入命令cd/dev进入到根目录的dev下,(dev是存储Linux的外部设备文件)输入命令ls查看当前目录下的文件,下图中的sda以及sda1就是我们刚刚插入的U盘(为啥是两个,我也不懂)如图 U盘的挂载回到根目录-------输入命令cd/查看根......
  • 5 个最常见的 Linux故障问题
    导读了解如何解决 Linux 桌面用户遇到的最常见的问题尽管绝大多数用户如预期地成功安装和操作了Linux,但不可避免地仍会有一些用户遇到问题。作为今年任务队列里的最后一篇文章,我认为在即将进入2016年时,总结一下人们所遇到的最常见的技术性的Linux问题会很有趣。我把这......
  • 飞腾杯-----Linux目录
    回到根目录-----输入命令cd /  在Linux系统中如下图回到“管理员用户的家目录”-----输入命令cd/root   在Linux系统中如下图打开Terminal后默认在/root目录下,如图 ......
  • docker build 构建时 alpinelinux 镜像权限错误
    问题使用dockerbuild构建镜像时,发生一个错误:“ERROR:https://dl-cdn.alpinelinux.org/alpine/v3.15/main:Permissiondenied”。部分日志如下:[2023-03-3014:51:12]Step3/16:RUNapkupdate&&apkupgrade&&apkaddmusl-devmakegccpython3[2023-03-3014:51:12......
  • Linux系统把时间类型值转换为数值型的方法是什么?
    在实际工作中,我们往往会遇到各式各样的需求,今天老男孩教育小编给大家介绍一下,如何把时间类型值转换为数值类型,以下是详细的内容:1.取子串函数格式:substr(c,n1.n2)功能:取字符串C第n1个字符起的n2个字符.返回值类型是字符型.例:取姓名字符串中的姓.store"......
  • Linux系统中创建文件常用的方法!
    众所周知,在Windows系统中可以直接右键新建文件,而在Linux系统中,想要创建文件并非易事,需要通过执行命令来完成,那么Linux系统中创建文件常用的方法有哪些?本文为大家介绍一下Linux系统下创建文件的8种方法,快来了解一下吧。1、重定向符号>通常重定向符号可以创建一个0kb的......