概述
在.dts文件中对设备及其属性的描述通常如以下这样:
/ {
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 Flashethernet@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 。
(二)中断控制器节点
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 的个数。例如:
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 控制器设备节点,例如:
sdhci@c8000400 {
status = "okay";
cd-gpios = <&gpio01 0>;
wp-gpios = <&gpio02 0>;
power-gpios = <&gpio03 0>;
bus-width = <4>;
};
而具体的设备驱动则通过以下方法来获取GPIO:
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的原型如下:
static inline int of_get_named_gpio(
struct device_node *np,
const char *propname, int index );
最后
以上就是自由香烟为你收集整理的ARM Linux设备树(3)的全部内容,希望文章能够帮你解决ARM Linux设备树(3)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复