当前Linux驱动开发,离不开devicetree的配置,它是干什么的呢?简单理解设备数,它就是一个板子配置信息描述文件。一开始内核并没有没有设备树,关于板端的设备信息都是在代码中描述,从而导致内核的arch目录下非常多板级相关的源文件,都是以.c或.h的格式定义。相对内核的其他而言,这些配置很多重复的,为了解决这样的问题,内核引进了devicetree,专门用来描述板级的配置信息,而内核的驱动则解析设备树获取板级信息进行配置,驱动干驱动的事情,完成了驱动和板级配置的解耦。那么设备树具体是怎样的呢?下面继续跟进。
设备树是描述板级硬件设备的数据结构文本,设备树文件一般以.dts或.dtsi为后缀的文件进行保存,通过节点和属性来描述板级资源。下面以一个dts文件进行介绍:
#include
#include /* dts中可以通过include引用其他的头文件,使用它们的定义 */
#include "sun8iw18p1-clk.dtsi" /* 可以引用其它的dts文件 */
#include "sun8iw18p1-pinctrl.dtsi"
/ { /* device tree,树总会有根,而/则是设备树的根,其他的都是节点,节点可以包含子节点 */
cpus { /* cpus作为根节点下的一个子节点,它也包含了cpu0、1两个子节点以及enable-method等属性信息 */
enable-method = "allwinner,sun8iw18p1";
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a7","arm,armv7";
reg = <0x0>;
enable-method = "psci";
/* 描述设备的时钟依赖信息,后续驱动可获取该信息 */
clocks = <&clk_pll_cpu>,<&clk_cpu>,<&clk_pll_periph0>;
clock-names = "pll","cpu","periph0";
operating-points-v2 = <&cpu_opp_l_table0>;
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0 &SYS_SLEEP_0>;
};
}
}
大家可以简单理解,设备树在开机的时候,系统会逐个解析dts并为之注册设备,而我们再编写驱动,当驱动与设备匹配时,则可以正常使用该设备。关于设备树,记住一点:只要符合语法规则即可,其他的都需要由驱动进行解析。所以,除了devicetree的信息外,驱动还需要对设备树进行解析,解析的接口下面介绍。
从设备树获取整形变量:
int of_property_read_u32(const struct device_node *np,
const char *propname,
u32 *out_value);
int of_property_read_u16(const struct device_node *np,
const char *propname,
u16 *out_value);
上述的接口可以从设备树中或者整形变量,比如:
// dts
dao: dao-test {
compatible = "dao-test";
num = <12>;
};
u32 value;
np指向dao节点,此时通过 of_property_read_u32(np, "num", &value)获取“num”指向的内容,此时value=12。
从设备树获取字符串变量:
int of_property_read_string(const struct device_node *np,
const char *propname,
const char **out_string);
而使用方式如下:
// dts
dao: dao-test {
compatible = "dao-test";
num = <12>;
str_info = "test_info";
};
const char *info;
np指向dao节点,此时通过 of_property_read_string(np, "str_info", &info)获取“str_info”指向的内容,此时info指向的内容是“test_info”。
更多的api可参考内核include/linux/of.h
中的接口进行使用。
设备树是在内核阶段使用的,编辑阶段,是dts的文本状态,而在内核使用时,则是将其转换为dtb二进制文件,系统在启动过程中,uboot再将其加载传递给内核进行使用。而这个设备树的转换则是通过dtc工具进行转换的,dtc工具一般在内核源码中有包含,dtc支持以下命令:
root@root#./scripts/dtc/dtc --help
Usage: dtc [options] <input file>
Options: -[qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv]
-q, --quiet
Quiet: -q suppress warnings, -qq errors, -qqq all
-I, --in-format <arg>
Input formats are:
dts - device tree source text
dtb - device tree blob
fs - /proc/device-tree style directory
-o, --out <arg>
Output file
-O, --out-format <arg>
Output formats are:
dts - device tree source text
dtb - device tree blob
asm - assembler source
-V, --out-version <arg>
Blob version to produce, defaults to 17 (for dtb and asm output)
-d, --out-dependency <arg>
Output dependency file
-R, --reserve <arg>
Make space for <number> reserve map entries (for dtb and asm output)
-S, --space <arg>
Make the blob at least <bytes> long (extra space)
-p, --pad <arg>
Add padding to the blob of <bytes> long (extra space)
-a, --align <arg>
Make the blob align to the <bytes> (extra space)
-b, --boot-cpu <arg>
Set the physical boot cpu
-f, --force
Try to produce output even if the input tree has errors
-i, --include <arg>
Add a path to search for include files
-s, --sort
Sort nodes and properties before outputting (useful for comparing trees)
-H, --phandle <arg>
Valid phandle formats are:
legacy - "linux,phandle" properties only
epapr - "phandle" properties only
both - Both "linux,phandle" and "phandle" properties
-W, --warning <arg>
Enable/disable warnings (prefix with "no-")
-E, --error <arg>
Enable/disable errors (prefix with "no-")
-@, --symbols
Enable generation of symbols
-A, --auto-alias
Enable auto-alias of labels
-T, --annotate
Annotate output .dts with input source file and line (-T -T for more details)
-h, --help
Print this help and exit
-v, --version
Print version and exit
dtc支持的参数较多,但我们常用的就是-I -i -O -o
这几个参数,通过他们指定输入输出文件和格式,得到dtb文件后再附加到内核镜像。