设备树的介绍和基础使用

设备树的介绍和使用


为什么引进设备树:

  • device部分是描述硬件的。一般device部分的代码会放在内核源码中arch/arm/plat-xxx和arch/arm/machxxx下面。但是随着Linux支持的硬件越来越多,在内核源码下关于硬件描述的代码也越来越多。并且每修改一下就要编译一次内核。
  • 长此以往Linux内核里面就存在了大量“垃圾代码”,而且非常多,这里说的“垃圾代码”是关于对硬件描述的代码。从长远看,这些代码对Linux内核本身并没有帮助,所以相当于Linux内核是“垃圾代码”。但是并不是说平台总线这种方法不好。
  • 为了解决这个问题,设备树就被引入到了Linux上。使用设备树来剔除相对内核来说的“垃圾代码”,既用设备树来描述硬件信息,用来替代原来的device部分的代码。虽然用设备树替换了原来的device部分,但是平台
    总线模型的匹配和使用基本不变。并且对硬件修改以后不必重新编译内核。直接需要将设备树文件编译成二进制文件,在通过bootloader传递给内核即可。

所以设备树就是用来描述硬件资源的文件。

基本名词解释

  1. DT:Device Tree //设备树
  2. FDT:Flattened Device Tree //开放设备树,起源于OpenFirmware (OF)
  3. dts: device tree source的缩写 //设备树源码
  4. dtsi: device tree source include的缩写 //通用的设备树源码
  5. dtb: device tree blob的缩写//编译设备树源码得到的文件
  6. dtc: device tree compiler的缩写 //设备树编译器

alt text

设备树编译格式:

编译设备树: dtc -I dts -0 dtb -o xxx.dtb xxx.dts

反编译设备树: dtc -I dtb -0 dts -o xxx.dts xxx.dtb

设备树的基本语法:

常用属性

alt text
根节点:

/dts-v1/;
/{

};

子节点:

格式:
    [label:]node-name[@unit-address]{
        [properties-list]
        [child-node-list]
    };

如:

nodel{ //子节点,名称node1
    nodel_child{
            //同级节点下不能出现相同名称
    };
};
  • 节点名称:在对节点进行命名的时候,一般要体现设备的类型,比如网口一般命名成ethernet,串口一般命名成uart,对于名称一般要遵循下面的命令格式。

格式:[标签]:<名称>[@<设备地址>]
其中,[标签]和[@<设备地址>]是可选项,<名称>是必选项。另外,这里的<设备地址>没有实际意义,只是让节点名称更人性化,更方便阅读。
举例:
  uart: serial@02288000 其中, uart就是这个节点标签,也叫别名, serial@02288000就是节点名称。

reg属性
reg属性可以来描述地址信息。比如寄存器的地址。reg属性的格式如下:

reg = <address1 lengthl address2 length2 address3 length3......>
举例:
reg = <0x02200000 0x4000>:
举例:
reg = <0x02200000 0x4000
0x02205000 0x4000>

#address-ce11#size-cells属性
#address-cel1和#size-cells用来描述子节点中的reg信息中的地址和长度信息

举例1:

node1{
    #address-cells =<1>;
    #size-cells = <0>:
    nodel-child{
        reg = <0>;
    }
}

#address-cells =<1>;#size-cells = <0>;所以reg里的属性值表示的是地址信息,数据为00️⃣

举例2:address=1,size=1,所以reg里的属性值一个表示地址信息,一个表示长度信息

node1{
    #address-cells = <1>;
    #size-cells =<1>;
    nodel-child{
        reg = <0x02200000 0x4000>;
    }
}

举例3:address=2,size=1,所以reg里表示的是两个地址信息

nodel{
    #address-cells =<2>
    #size-cells =<0>:
    nodel-child{
        reg = <0x00 0x01>;
    }
}

model属性的值是一个字符串,一般用model描述一些信息。比如设备的名称,名字等

举例1:

model = "wm8960-audio"

举例2:

model = "This is Linux board"

status属性是和设备的状态有关系的,status的属性值是字符串。属性值有下面几个状态可选:

alt text

compatible属性是非常重要的一个属性。compatible是用来和驱动进行匹配的。匹配成功以后会执行驱动中的probe函数。
举例:

compatible ="nihao","hello";

在匹配的时候会先使用第一个值nihao进行匹配,如果没有就会使用第二个值hello进行匹配。

特殊节点aliases:用来定义别名

特殊节点aliases用来定义别名。定义别名的目的就是为了方便引用节点。当然,除了使用aliases来命名别用,也可以在对节点命名的适合添加标签来命名别名。

举例:

aliases{
    mmc0 = &sdmmc0;
    mmcl = &sdmmc1;
    mmc2 = &sdhci;
    serial0="/simple@fe000000/serial@llc500”;
}

chosen节点用来uboot给内核传递参数。重点是bootargs参数。chosen节点必须是根节点的子节点。

举例:

chosen{
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200”;
}

设备树中规定的属性有时候并不能满足我们的需求,这时候我们可以自定义属性。
举例:自定义一个管教标号的属性pinnum。

pinnum =<0 12 3 4>;

特殊属性ranges:地址映射

ranges两种格式:

  1. 一种带参数 ranges= <child-bus-address parent-bus-address length>
    按照规则映射
  2. 一种不带参数 ranges;
    1:1映射,内存区域,表示不需要映射
  3. 没有ranges属性
    表示设备只能被父节点访问

参数:

  • child-bus-address:子地址物理空间的起始地址。由 ranges 所在节点“#address-cells”属性决定该地址所占的字长
  • parent-bus-address:父地址物理空间的起始地址。由 ranges 的父节“#address-cells”属性决定该地址所占的字长
  • length:映射的大小,由ranges 的父节点“#size-cells”属性决定该地址所占的字长

实例分析:如何读取数据格式

alt text

  作用:将子地址空间映射到父地址的空间。

  使用场景:当子地址的物理空间和父地址的物理空间不在同一个总线上时,使用ranges属性来描述子地址到父地址的映射关系。
  比如一些非内存映射的设备,可以类比为CPU不能直接访问的设备(内存映射设备类比可被CPU直接访问,1:1映射),需要地址映射才可以访问:好比I2c控制器下面挂载的I2c从设备,是通过I2c的协议通讯的,是串行通信方式,而CPU和I2c控制器是并行通信方式,所以CPU不能直接访问I2c控制器,需要通过I2c协议进行访问。I2c下的设备,只能被其控制器访问。
alt text

  使用方法:在子地址的节点中使用ranges属性来描述子地址到父地址的映射关系。

ranges=<0x0 0x20 0x100>       

把子地址空间(0x0–(0x0+0x100))映射到父地址空间 (0x10–(0x20+0x100))

设备树示例分析:中断

alt text

  1. 在中断控制器中,必须有一个属性#interrupt-cells,表示其他节点如果使用这个中断控制器需要几个cell来表示使用哪一个中断。
  2. 在中断控制器中,必须有一个属性interrupt-controller,表示他
    是中断控制器。
  3. 在设备树中使用中断,需要使用属性interrupt-parent=<&XXXX>表是中断信号链接的是哪个中断控制器。接着使用interrupts属性来表示中断引脚和触发方式。
  4. 注:interrupt里有几个cell,是由interrupt-parent对应的中断控制
    器里面的#interrupt-cells属性决定。

中断描述编写:

RK处理器的中断示例:rk3568.dtsi公共的设备树资源信息
alt text

	interrupt-controller;
	#interrupt-cells = <2>;
    //表示引用该节点,并使用中断控制器的话,需要在interrupt中写入两个属性来描述中断信息

例如:
alt text
interrupts = <RK_PB5 IRQ_TYPE_EDGE_RISING>;
描述该中断资源:是PB5引脚,中断触发方式是上升沿触发。

注意:在设备树的编写中也可以像c语言那样没使用.h中的宏定义,也需要像c语言那样将头文件包含进来
alt text

示例分析:GPIO

alt text

  1. 在GPIO控制器中,必须有一个属性##gpio-cells,表示其他节点如果使用这个GPIO控制器需要几个cell来表示使用哪一个GPIO。
  2. 在GPIO控制器中,必须有一个属性gpio-controller,表示他
    是GPIO控制器。
  3. 在设备树中使用GPIO,需要使用属性data-gpios=<&gpio1 12 0>
    指定具体的GPIO引脚。data-gpios属性可以为自定义属性。
    简化:
gpiol: gpiol{
 gpio-controller;
 #gpio-cells =<2>;
}
//同时描述多个
 data-gpios = <&gpio1 12 0>,<&gpiol 15 0>:

led灯的描述编写:

alt text
gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
引用gpio0,两个属性值表述具体的引脚信息
注意:设备树是用来描述硬件资源的,并不是在实际的使用中对资源做了对应的初始化定义。驱动攻城狮🦁在驱动中获取设备树定义的资源后,具体怎么使用,要看驱动的编写。

Pinctrl设置复用关系

  • Linux内核提供了pinctrl子系统,pinctrl是pincontroller的缩写,目的是为了统一各芯片原厂的pin脚管理。所以一般pinctr1子系统的驱动是由芯片原厂的BSP攻城狮🦁实现。

  • 有了pinctr1子系统以后,驱动攻城狮🦁就可以通过配置设备树使用pinctrl子系统去设置管脚的复用以及管脚的电气属性。

    alt text

例1:

pinctrl-names = default".
pinctrl-0 = <&pinctrl hog 1>;

解析:使用pinctrl-names表示设备的状态。这里只有一个default状态,default为第0个状态。pinctrl-0 =<&pinctrl_hog_1>表示第0个状态default对应得引脚在pinctrl_hog_1节点中配置。

例2:

pinctrl-names = "default","wake up"
pinctrl-0 = <&pinctrl_hog_1>;
pinctrl-1 = <&pinctrl_hog_2>;

解析:使用pinctrl-names表示设备的状态。这里有default和wake up俩个状态,default为第0个状态,wake up为第1个状态。pinctrl-0 =<&pinctrl_hog_1>表示第0个状态default对应得引脚在pinctrl_hog_1节点中配置。pinctrl-1同理。

例3:

pinctrl-names = "default".
pinctrl-0 = <&pinctrl_hog_1 &pinctrl_hog_2>;

解析:使用pinctrl-names表示设备的状态。这里只有一个default状态,default为第0个状态。pinctrl-0 =<&pinctrl_hog_1>表示第0个状态default对应得引脚在pinctrl_hog_l和pinctrl_hog_2俩个节点中配置

            ----------------------示例------------------------

alt text
alt text
alt text

示例分析:LED灯的描述:

Orangepi-3b:使用Rk3566的处理器,查看设备树的LED描述:
//客户端:
alt text
//服务端的配置:
alt text

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想和我重名?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值