设备树的概念(二):表示和寻址设备
表示和寻址设备
每个设备在DT中至少有一个节点。有些属性对于许多设备类型都是通用的,特别是位于内核已知总线(SPI、I2C、Platform、MDIO等等)上的设备。这些属性是reg、#address-cells和#size-cells。这些属性的目的是在它们所在的总线上进行设备寻址。也就是说,主要的寻址属性是reg,这是一个通用属性,其含义取决于设备所在的总线。size-cell和address-cell前面的#(hash)可以转换为length。
每个可寻址设备都具有reg属性,该属性是一个元组列表,形式为reg = <address0 size0 [address1size1] [address2size2]…>;,其中每个元组表示设备使用的地址范围。#size-cells表示使用多少个32位单元来表示大小,如果与大小无关,则可以为0。另一方面,#address-cells表示使用多少个32位单元来表示地址。换句话说,每个元组的address元素根据#address-cell来解释;size元素也是如此,它根据#size-cell进行解释。
实际上,可寻址设备继承了它们父节点的#size-cell和#address-cell,父节点是代表总线控制器的节点。给定设备中#size cell和#address-cell的存在不会影响设备本身,但会影响它的子设备。换句话说,在解释给定节点的reg属性之前,必须知道父节点的#address-cells和#size-cells值。父节点可以自由定义任何适合设备子节点的寻址方案。
SPI和I2C寻址
SPI和I2C设备都属于非内存映射设备,因为它们的地址不能被CPU访问。相反,父设备的驱动程序(即总线控制器驱动程序)将代表CPU执行间接访问。每个I2C/SPI设备总是表示为该设备所在的I2C/SPI总线节点的子节点。对于非内存映射的设备,#size-cells属性为0,寻址元组中的size元素为空。这意味着这种设备的reg属性总是只有一个单元:
&i2c3 {
[...]
status = "okay";
temperature-sensor@49 {
compatible = "national,lm73";
reg = <0x49>;
};
pcf8523: rtc@68 {
compatible = "nxp,pcf8523";
reg = <0x68>;
};
};
&ecspi1 {
fsl,spi-num-chipselects = <3>;
cs-gpios = <&gpio5 16 0>, <&gpio5 17 0>, <&gpio5 18 0>;
status = "okay";
[...]
ad7606r8_0: ad7606r8@1 {
compatible = "ad7606-8";
reg = <1>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio4>;
interrupts = <30 0x0>;
convst-gpio = <&gpio6 18 0>;
};
};
如果你查看soc级别文件arch/arm/boot/dts/imx6qdl.dtsi,你将注意到i2c和spi节点中的#size-cells和#address-cells分别被设置为0和1,这两个节点分别是上面列举的i2c和spi设备的父节点。这有助于我们理解它们的reg属性,即address值只有一个元素,size值没有。
I2C设备的reg属性用于指定设备在总线上的地址。对于SPI设备,reg表示在控制节点的片选列表中分配给该设备的片选的索引。例如ad7606r8 ADC,片选索引为1,对应于cs-gpios中的<&gpio5 17 0>,cs-gpios是控制节点中的芯片选择列表。
为什么以I2C/SPI节点的phandle为例?因为I2C/SPI设备应该在板级文件(.dts)中声明,而I2C/SPI总线控制器则在soc级文件(.dtsi)中声明。
平台设备寻址
本文介绍简单内存映射设备,这些设备的内存可以被CPU访问。这里,reg属性仍然定义了设备的地址,这是一个可以访问设备的内存区域列表。每个区域都用一个cells元组表示,其中第一个cell是内存区域的基址,第二个cell是该区域的大小。然后它的形式是reg = <base0 length0 [base1 length1] [address2 length2]…>。每个元组表示设备使用的一个地址范围。
在现实世界中,如果不知道其他两个属性#size-cells和#address-cells的值,就不应该分解reg属性。#size-cells告诉我们每个子reg元组中长度字段有多大。#address-cell也是一样,它告诉我们必须使用多少cell来指定一个地址。
这种设备应该在一个特殊值的节点中声明,compatible = "simple-bus",意思是一个简单的内存映射总线,没有特定的处理或驱动程序:
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
aips-bus@02000000 { /* AIPS1 */
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02000000 0x100000>;
[...];
spba-bus@02000000 {
compatible = "fsl,spba-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02000000 0x40000>;
[...]
};
ecspi1: ecspi@02008000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
reg = <0x02008000 0x4000>;
[...]
};
i2c1: i2c@021a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
reg = <0x021a0000 0x4000>;
[...]
};
};
};
在前面的例子中,其父节点在compatible属性中具有simple-bus的子节点将被注册为平台设备。你还可以看到I2C和SPI总线控制器如何通过设置#size-cells = <0>;因为这与他们无关。查找binding信息的一个众所周知的位置是在内核设备树的文档中:documentation /devicetree/bindings/。
本文来自博客园,作者:闹闹爸爸,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/17204159.html