linux驱动开发学习笔记十二:设备树中节点的命名格式和常见属性

一、节点的命名格式

1 / { 
2     aliases { 
3        can0 = &flexcan1; 
4     };
5 
6     cpus { 
7        #address-cells = <1>;
8        #size-cells = <0>;
9 
10       cpu0: cpu@0 {
11          compatible = "arm,cortex-a7";
12          device_type = "cpu";
13          reg = <0>;
14        };
15    };
16
17    intc: interrupt-controller@00a01000 {
18       compatible = "arm,cortex-a7-gic";
19       #interrupt-cells = <3>;
20       interrupt-controller;
21       reg = <0x00a01000 0x1000>,
22             <0x00a02000 0x100>;
23    };
24 }
  • 第 1 行,“/”是根节点,每个设备树文件只有一个根节点。其实在dtsdtsi文件中都有根节点,但是并不会出错,因为这两个“/”根节点的内容会合并到一个根节点中。

  • 第 2、6 和 17 行,aliasescpusintc是三个子节点,在设备树中节点命名格式如下:

node-name@unit-address

其中“node-name”是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的功能,比如“uart1”就表示这个节点是 UART1外设。“unit-address”一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话“unit-address”可以不要,比如“cpu@0”“interrupt-controller@00a01000”

  • 但是我们在上述代码中我们看到的节点命名却如下所示:
cpu0:cpu@0

上述命令并不是“node-name@unit-address”这样的格式,而是用“:”隔开成了两部分,“:”前面的是节点标签(label)“:”后面的才是节点名字,格式如下所示:

label: node-name@unit-address

引入label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字。再比如节点 “intc: interrupt-controller@00a01000”,节点 labelintc,而节点名字就很长了,为“interrupt-controller@00a01000”。很明显通过&intc来访问“interrupt-controller@00a01000”这个节点要方便很多!

  • 第 10 行,cpu0 也是一个节点,只是 cpu0cpus的子节点。每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流。设备树源码中常用的几种数据形式如下所示:

1、字符串

compatible = "arm,cortex-a7";

上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”

2、32 位无符号整数

reg = <0>;

上述代码设置 reg属性的值为 0,reg 的值也可以设置为一组值,比如:

reg = <0 0x123456 100>;

3、字符串列表

属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,如下所示:

compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

上述代码设置属性 compatible 的值为“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”

二、常见属性

节点是由一堆的属性组成,节点都是具体的设备,不同的设备需要的属性不同,用户可以自定义属性。除了用户自定义属性,有很多属性是标准属性,Linux 下的很多外设驱动都会使用这些标准属性。

  • 1、compatible 属性

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

"manufacturer,model"

其中 manufacturer 表示厂商,model一般是模块对应的驱动名字。比如imx6ull-alientek-emmc.dtssound节点是 I.MX6U-ALPHA 开发板的音频设备节点,I.MX6U-ALPHA开发板上的音频芯片采用的欧胜(WOLFSON)出品的 WM8960sound节点的 compatible 属性值如下:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

属性值有两个,分别为“fsl,imx6ul-evk-wm8960”“fsl,imx-audio-wm8960”,其中“fsl”表示厂商是飞思卡尔,“imx6ul-evk-wm8960”“imx-audio-wm8960”表示驱动模块名字。sound这个设备首先使用第一个兼容值在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件,如果没有找到的话就使用第二个兼容值查找,直到找到或者查找完整个 Linux 内核也没有找到对应的驱动。

一般驱动程序文件都会有一个OF 匹配表,此 OF 匹配表保存着一些 compatible值,如果设备节点的 compatible 属性值和OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。比如在文件imx-wm8960.c中有如下内容
在这里插入图片描述
第 632~635 行的数组 imx_wm8960_dt_ids 就是 imx-wm8960.c这个驱动文件的匹配表,此匹配表只有一个匹配值“fsl,imx-audio-wm8960”。如果在设备树中有哪个节点的compatible 属性值与此相等,那么这个节点就会使用此驱动文件。

第 642 行,wm8960采用了platform_driver驱动模式,关于 platform_driver驱动后面会讲解。此行设置.of_match_tableimx_wm8960_dt_ids,也就是设置这个platform_driver所使用的OF 匹配表。

  • 2、model 属性

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

model = "wm8960-audio";
  • 3、status 属性

status属性看名字就知道是和设备状态有关的,status属性值也是字符串,字符串是设备的状态信息,可选的状态如下表所示:
在这里插入图片描述

  • 4、#address-cells 和#size-cells 属性

这两个属性的值都是无符号 32 位整形,#address-cells#size-cells这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。#address-cells属性值决定了子节点reg 属性中地址信息所占用的字长(32 位),#size-cells属性值决定了子节点 reg属性中长度信息所占的字长(32 位)。#address-cells#size-cells 表明了子节点应该如何编写reg属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度,reg属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>

每个“address length”组合表示一个地址范围,其中 address是起始地址,length是地址长度,#address-cells表明 address这个数据所占用的字长,#size-cells表明length这个数据所占用的字长,比如:
在这里插入图片描述
第 3,4 行,节点 spi4#address-cells = <1>#size-cells = <0>,说明spi4的子节点reg 属性中起始地址所占用的字长为 1,地址长度所占用的字长为 0。

第 8 行,子节点gpio_spi: gpio_spi@0reg属性值为 <0>,因为父节点设置了#address-cells = <1>#size-cells = <0>,因此 addres=0,没有length的值,相当于设置了起始地址,而没有设置地址长度。

第 14,15 行,设置aips3: aips-bus@02200000节点#address-cells = <1>#size-cells = <1>,说明aips3: aips-bus@02200000节点起始地址长度所占用的字长为 1,地址长度所占用的字长也为 1。

第 19 行,子节点 dcp: dcp@02280000reg属性值为<0x02280000 0x4000>,因为父节点设置了#address-cells = <1>#size-cells = <1>address= 0x02280000length= 0x4000,相当于设置了起始地址为0x02280000,地址长度为0x40000

  • 5、reg 属性

reg属性前面已经提到过了,reg属性的值一般是(address,length)对。reg属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息,比如在imx6ull.dtsi中有如下内容:
在这里插入图片描述
上述代码是节点uart1uart1节点描述了I.MX6ULLUART1相关信息,重点是第 326 行 的reg 属性。其中uart1的父节点 aips1: aips-bus@02000000设置了#address-cells = <1>#size-cells = <1>,因此reg属性中address=0x02020000length=0x4000。查阅《I.MX6ULL 参考手册》可知,I.MX6ULLUART1寄存器首地址为0x02020000,但是 UART1的地址长度(范围)并没有 0x4000这么多,这里我们重点是获取 UART1寄存器首地址。

  • 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确定此地址长度所占用的字长。如果ranges属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换,对于我们所使用的.MX6ULL 来说,子地址空间和父地址空间完全相同,因此会在imx6ull.dtsi中找到大量的值为空的ranges 属性,如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、 根节点 compatible 属性

每个节点都有 compatible 属性,根节点“/”也不例外,imx6ull-alientek-emmc.dts文件中根节点的 compatible属性内容如下所示:

//示例代码 43.3.4.1 imx6ull-alientek-emmc.dts 根节点 compatible 属性
14 / {
15       model = "Freescale i.MX6 ULL 14x14 EVK Board";
16       compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
......
148 }

可以看出,compatible有两个值:“fsl,imx6ull-14x14-evk”“fsl,imx6ull”。前面我们说了,设备节点的 compatible属性值是为了匹配 Linux 内核中的驱动程序,那么根节点中的 compatible属性是为了做什么工作的? 通过根节点的compatible属性可以知道我们所使用的设备,一般第一个值描述了所使用的硬件设备名字,比如这里使用的是“imx6ull-14x14-evk”这个设备,第二个值描述了设备所使用的 SOC,比如这里使用的是“imx6ull”这颗 SOC。Linux 内核会通过根节点的compoatible 属性查看是否支持此设备,如果支持的话设备就会启动 Linux 内核。

猜你喜欢

转载自blog.csdn.net/qq_39507748/article/details/105877952