我是靠谱客的博主 自由香烟,这篇文章主要介绍ARM Linux设备树(3),现在分享给大家,希望可以做个参考。

在.dts文件中对设备及其属性的描述通常如以下这样:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/ { compatible = "acme, coyotes-revenge"; #address-cells = <1>; #size-cells = <1>; ... cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { compatible = "arm, cortex-a9"; reg = <0>; }; cpu@1 { compatible = "arm, cortex-a9"; reg = <1>; }; }; serial1@101f0000 { compatible = "arm,pl1011"; reg = <0x101f0000 0x1000>; interrupts = < 1 0 >; }; ... external-bus { #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0x10100000 0x1000 // ChipSelect 1, Ethernet 1 0 0x10160000 0x1000 // ChipSelect 2, i2c controller 2 0 0x30000000 0x100000>; // ChipSelect 3, NOR Flash ethernet@0,0 { compatible = "smc,smc91c111"; reg = <0 0 0x1000> interrupts = < 5 2 >; }; ... }; };

其中compatible代表设备节点的兼容属性(略);

reg代表地址编码,reg组织形式为:

reg = <address1 length1 [address2 length2] [address3 length3] ... >

以上的每组 “address length” 表征了设备使用的一个地址范围。

address为1个或者多个32-bit的整型(即cell);

length的含义是从 address 到 address + length - 1 的地址范围都属于该设备节点;

(一)地址编码

前述 address 和 length 字段是可变长度的,父节点的 #address-cells 和 #size-cells 分别决定了子节点reg属性的 address 字段的个数和 length 字段的个数。

若#size-cells = <0>,则表示length字段为空。

在上述.dts文件描述中,root节点的:#address-cells = <1>; #size-cells = <1>; 意味着root节点下面的各个子节点的 address字段和 length字段的个数分别为1。例如,serial1这个子节点:

reg = <0x101f0000 0x1000>

它就是符合:address字段的个数为1,length字段的个数为1。

而 cpus 这个子节点它又包含了子节点,并且 cpus 的 reg 属性是:#address-cells = <1>; #size-cells = <0>; 所以 cpus 的子节点 cpu 的reg属性为:

reg = <0> 

或者 reg = <1>

即 length 字段为空。

接着,再看 root 节点的 external-bus 子节点:

external-bus {
    #address-cells = <2>;
    #size-cells = <1>;
    ranges = <0 0 0x10100000 0x1000        // ChipSelect 1, Ethernet
                     1 0 0x10160000 0x1000        // ChipSelect 2, i2c controller
                     2 0 0x30000000 0x100000>; // ChipSelect 3, NOR Flash

    ethernet@0,0 {
        compatible = "smc,smc91c111";
        reg = <0 0 0x1000>
        interrupts = < 5 2 >;
    };
    ...
   
};

它代表 address 字段的个数为2,而 length 字段的个数为1。意味着其下的 ethernet 子节点的 reg 属性形如:

reg = <0 0 0x1000>;

值得说明的是,通常 root 节点的直接子节点的 address 区域就直接位于 CPU 的内存区域,而经过总线桥以后的 address 往往需要经过转换才能对应到 CPU 的内存映射区域。

在以上 external-bus 节点的描述中,ranges 表示地址转换表。

ranges 中的每个项目是:子 address + 父 address (子 address 的地址映射)及映射的大小。

具体而言,external-bus 这个子节点的 #address-cells 值为2,而其父节点(root 节点)的 #address-cells 值为1,所以 ranges 中:

0 0 0x10100000 0x1000

前面两个cell (即 0 0 )代表总线桥上面片选 0 和 偏移地址 0;

第3个cell (即 0x10100000 )代表总线桥上面片选 0 和 偏移地址 0 的地址空间被映射到了 CPU 本地总线的 0x10100000 位置,也就是所谓的 “父 address” ;

第4个cell(即 0x1000 )代表地址空间映射的大小为 0x1000 。

(二)中断控制器节点

复制代码
1
2
3
4
5
6
intc: interrupt-controller@10140000 { compatible = "arm,pl190"; reg = <0x10140000 0x1000>; interrupt-controller; #interrupt-cells = <2>; };

上述 #interrupt-cells 与 #address-cells 和 #size-cells 相似,它表示连接到此中断控制器的设备的中断属性的 cell 个数。

在整个设备树中,与中断相关的属性还有:

1)interrput-parent属性

设备节点通过它来指定它所依附的中断控制器的phandle,当设备节点没有指定 interrupt-parent 属性之时,则从父级节点继承。

2)interrupts属性

设备节点通过它指定中断号、触发方法等,这个属性具体包含多少个 cell,由它依附的中断控制器节点的 #interrupt-cells 属性决定。而每个 cell 具体又是什么含义,一般由驱动的实现决定,而且也会在设备树的绑定文档中进行说明。

(三)GPIO控制器节点

对于GPIO控制器而言,其对应的设备需声明 gpio-controller 属性,并设置 #gpio-cell 的个数。例如:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pinctrl@80018000 { compatible = "fsl,imx28-pinctrl","simple-bus"; reg = <0x80018000 2000>; gpio0: gpio@0 { compatible = "fsl,imx28-gpio"; interrupts = <127>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; }; gpio1: gpio@0 { compatible = "fsl,imx28-gpio"; interrupts = <126>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; }; };

其中,#gpio-cells 为2,第一个 cell 为 GPIO 号,第二个 cell 为 GPIO 的极性:为0的时候是高电平有效,为1的时候是低电平有效。

使用GPIO的其他设备可以通过定义 xxx-gpios 属性来引用 GPIO 控制器设备节点,例如:

复制代码
1
2
3
4
5
6
7
sdhci@c8000400 { status = "okay"; cd-gpios = <&gpio01 0>; wp-gpios = <&gpio02 0>; power-gpios = <&gpio03 0>; bus-width = <4>; };

而具体的设备驱动则通过以下方法来获取GPIO:

复制代码
1
2
3
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); power_gpio = of_get_named_gpio(np, "power-gpios", 0);

of_get_named_gpio这个API的原型如下:

复制代码
1
2
3
static inline int of_get_named_gpio( struct device_node *np, const char *propname, int index );

最后

以上就是自由香烟最近收集整理的关于ARM Linux设备树(3)的全部内容,更多相关ARM内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部