买医疗产品的网站建设,wordpress 获取副标题,任城网络推广教程,重庆响应式网页建设公司首先说明#xff0c;设备树不可能用来写驱动。
设备树只是用来给内核里的驱动程序#xff0c;指定硬件的信息。比如LED驱动#xff0c;在内核的驱动程序里去操作寄存器#xff0c;但是操作哪一个引脚#xff1f;这由设备树指定。
需要编写设备树文件(dts: device tree s…首先说明设备树不可能用来写驱动。
设备树只是用来给内核里的驱动程序指定硬件的信息。比如LED驱动在内核的驱动程序里去操作寄存器但是操作哪一个引脚这由设备树指定。
需要编写设备树文件(dts: device tree source)它需要编译为dtb(device tree blob)文件内核使用的是dtb文件。
1.设备树示例 它对应的dts文件如下
2. Devicetree格式
2.1 DTS文件的格式
DTS文件布局(layout):
/dts-v1/; // 表示版本
[memory reservations] // 格式为: /memreserve/ address length;
/ {[property definitions][child nodes]
};2.2 node的格式
设备树中的基本单元被称为“node”其格式为
[label:] node-name[unit-address] {[properties definitions][child nodes]
};label是标号可以省略。label的作用是为了方便地引用node比如
/dts-v1/;
/ {uart0: uartfe001000 {compatiblens16550;reg0xfe001000 0x100;};
};可以使用下面2种方法来修改uartfe001000这个node
// 在根节点之外使用label引用node
uart0 {status “disabled”;
};
或在根节点之外使用全路径
{/uartfe001000} {status “disabled”;
};2.3 properties的格式
简单地说properties就是“namevalue”value有多种取值方式。 1Property格式1:
[label:] property-name value;2Property格式2(没有值):
[label:] property-name;3Property取值只有3种:
arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示),
string(字符串),
bytestring(1个或多个字节)示例: 1Arrays of cells : cell就是一个32位的数据用尖括号包围起来
interrupts 17 0xc;264bit数据使用2个cell来表示用尖括号包围起来:
clock-frequency 0x00000001 0x00000000;3A null-terminated string (有结束符的字符串)用双引号包围起来:
compatible simple-bus;4A bytestring(字节序列) 用中括号包围起来:
local-mac-address [00 00 12 34 56 78]; // 每个byte使用2个16进制数来表示
local-mac-address [000012345678]; // 每个byte使用2个16进制数来表示5可以是各种值的组合, 用逗号隔开:
compatible ns16550, ns8250;
example 0xf00f0000 19, a strange property format;3. dts文件包含dtsi文件
设备树文件不需要我们从零写出来内核支持了某款芯片比如imx6ull在内核的arch/arm/boot/dts目录下就有了能用的设备树模板一般命名为xxxx.dtsi。“i”表示“include”被别的文件引用的。
我们使用某款芯片制作出了自己的单板所用资源跟xxxx.dtsi是大部分相同小部分不同所以需要引脚xxxx.dtsi并修改。
dtsi文件跟dts文件的语法是完全一样的。
dts中可以包含.h头文件也可以包含dtsi文件在.h头文件中可以定义一些宏。 示例
/dts-v1/;#include dt-bindings/input/input.h
#include imx6ull.dtsi/ {
……
};
4. 常用的属性
4.1 #address-cells、#size-cells
cell指一个32位的数值 address-cellsaddress要用多少个32位数来表示 size-cellssize要用多少个32位数来表示。
比如一段内存怎么描述它的起始地址和大小 下例中address-cells为1所以reg中用1个数来表示地址即用0x80000000来表示地址size-cells为1所以reg中用1个数来表示大小即用0x20000000表示大小
/ {
#address-cells 1;
#size-cells 1;
memory {
reg 0x80000000 0x20000000;};
};4.2 compatible
“compatible”表示“兼容”对于某个LED内核中可能有A、B、C三个驱动都支持它那可以这样写
led {
compatible “A”, “B”, “C”;
};内核启动时就会为这个LED按这样的优先顺序为它找到驱动程序A、B、C。
根节点下也有compatible属性用来选择哪一个“machine desc”一个内核可以支持machine A也支持machine B内核启动后会根据根节点的compatible属性找到对应的machine desc结构体执行其中的初始化函数。
compatible的值建议取这样的形式“manufacturer,model”即“厂家名,模块名”。
注意machine desc的意思就是“机器描述”学到内核启动流程时才涉及。
4.3 model
model属性与compatible属性有些类似但是有差别。
compatible属性是一个字符串列表表示可以你的硬件兼容A、B、C等驱动 model用来准确地定义这个硬件是什么。
比如根节点中可以这样写
/ {compatible samsung,smdk2440, samsung,mini2440;model jz2440_v3;
};它表示这个单板可以兼容内核中的“smdk2440”也兼容“mini2440”。 从compatible属性中可以知道它兼容哪些板但是它到底是什么板用model属性来明确。
4.4 status
dtsi文件中定义了很多设备但是在你的板子上某些设备是没有的。这时你可以给这个设备节点添加一个status属性设置为“disabled”
uart1 {status disabled;
};4.5 reg
reg的本意是register用来表示寄存器地址。
但是在设备树里它可以用来描述一段空间。反正对于ARM系统寄存器和内存是统一编址的即访问寄存器时用某块地址访问内存时用某块地址在访问方法上没有区别。
reg属性的值是一系列的“address size”用多少个32位的数来表示address和size由其父节点的#address-cells、#size-cells决定。
示例
/dts-v1/;
/ {#address-cells 1;#size-cells 1; memory {reg 0x80000000 0x20000000;};
};5. 常用的节点(node)
5.1 根节点
dts文件中必须有一个根节点
/dts-v1/;
/ {model SMDK24440;compatible samsung,smdk2440;#address-cells 1;#size-cells 1;
};根节点中必须有这些属性
#address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size)
compatible // 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备// 即这个板子兼容哪些平台 // uImage : smdk2410 smdk2440 mini2440 machine_desc model // 咱这个板子是什么// 比如有2款板子配置基本一致, 它们的compatible是一样的// 那么就通过model来分辨这2款板子5.2 CPU节点
一般不需要我们设置在dtsi文件中都定义好了
cpus {#address-cells 1;#size-cells 0;cpu0: cpu0 {.......}
};5.3 memory节点
芯片厂家不可能事先确定你的板子使用多大的内存所以memory节点需要板厂设置比如
memory {
reg 0x80000000 0x20000000;
};5.4 chosen节点
我们可以通过设备树文件给内核传入一些参数这要在chosen节点中设置bootargs属性
chosen {bootargs noinitrd root/dev/mtdblock4 rw init/linuxrc consolettySAC0,115200;
};6. 内核对设备树的处理
从源代码文件dts文件开始设备树的处理过程为 ① dts在PC机上被编译为dtb文件 ② u-boot把dtb文件传给内核 ③ 内核解析dtb文件把每一个节点都转换为device_node结构体 ④ 对于某些device_node结构体会被转换为platform_device结构体。
6.1 dtb中每一个节点都被转换为device_node结构体 根节点被保存在全局变量of_root中从of_root开始可以访问到任意节点。
6.2 哪些设备树节点会被转换为platform_device
1根节点下含有compatile属性的子节点
2含有特定compatile属性的节点的子节点 如果一个节点的compatile属性它的值是这4者之一“simple-bus”,“simple-mfd”,“isa”,“arm,amba-bus”,
那么它的子结点(需含compatile属性)也可以转换为platform_device。
3总线I2C、SPI节点下的子节点不转换为platform_device 某个总线下到子节点应该交给对应的总线驱动程序来处理, 它们不应该被转换为platform_device。
比如以下的节点中 /mytest会被转换为platform_device, 因为它兼容simple-bus它的子节点/mytest/mytest0 也会被转换为platform_device
/i2c节点一般表示i2c控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver; /i2c/at24c02节点不会被转换为platform_device, 它被如何处理完全由父节点的platform_driver决定, 一般是被创建为一个i2c_client。
类似的也有/spi节点, 它一般也是用来表示SPI控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;
/spi/flash0节点不会被转换为platform_device, 它被如何处理完全由父节点的platform_driver决定, 一般是被创建为一个spi_device。
/ {mytest {compatile mytest, simple-bus;mytest0 {compatile mytest_0;};};i2c {compatile samsung,i2c;at24c02 {compatile at24c02; };};spi {compatile samsung,spi; flash0 {compatible winbond,w25q32dw;spi-max-frequency 25000000;reg 0;};};};6.3 怎么转换为platform_device
内核处理设备树的函数调用过程这里不去分析我们只需要得到如下结论 1platform_device中含有resource数组, 它来自device_node的reg, interrupts属性; 2platform_device.dev.of_node指向device_node, 可以通过它获得其他属性
7. platform_device如何与platform_driver配对
从设备树转换得来的platform_device会被注册进内核里以后当我们每注册一个platform_driver时它们就会两两确定能否配对如果能配对成功就调用platform_driver的probe函数。 1最先比较是否强制选择某个driver 比较platform_device.driver_override和platform_driver.driver.name 可以设置platform_device的driver_override强制选择某个platform_driver。 2然后比较设备树信息 比较platform_device.dev.of_node和platform_driver.driver.of_match_table。
由设备树节点转换得来的platform_device中含有一个结构体of_node。它的类型如下 如果一个platform_driver支持设备树它的platform_driver.driver.of_match_table是一个数组类型如下 使用设备树信息来判断dev和drv是否配对时 首先如果of_match_table中含有compatible值就跟dev的compatile属性比较若一致则成功否则返回失败
其次如果of_match_table中含有type值就跟dev的device_type属性比较若一致则成功否则返回失败
最后如果of_match_table中含有name值就跟dev的name属性比较若一致则成功否则返回失败。
而设备树中建议不再使用devcie_type和name属性所以基本上只使用设备节点的compatible属性来寻找匹配的platform_driver。
3接下来比较platform_device_id 比较platform_device.name和platform_driver.id_table[i].nameid_table中可能有多项。
platform_driver.id_table是“platform_device_id”指针表示该drv支持若干个device它里面列出了各个device的{.name, .driver_data}其中的“name”表示该drv支持的设备的名字driver_data是些提供给该device的私有数据。
4最后比较platform_device.name和platform_driver.driver.name platform_driver.id_table可能为空这时可以根据platform_driver.driver.name来寻找同名的platform_device。
一个图概括所有的配对过程