查看“设备树详解”的源代码
←
设备树详解
跳转至:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
==简介== 在传统Linux内核中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码对内核来讲只不过是垃圾代码。而采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。导致ARM的merge工作量较大。 之后经过一些讨论,对ARM平台的相关code做出如下相关规范调整,这个也正是引入DTS的原因。 1、ARM的核心代码仍然保存在arch/arm目录下 2、ARM SoC core architecture code保存在arch/arm目录下 3、ARM SOC的周边外设模块的驱动保存在drivers目录下 4、ARM SOC的特定代码在arch/arm/mach-xxx目录下 5、ARM SOC board specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。 本质上,Device Tree改变了原来用code方式将硬件配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个参数信息传递给kernel,以便kernel可以有较大的灵活性。在linux kernel中,Device Tree的设计目标就是如此。 在devie tree中,可描述的信息包括: 1、CPU的数量和类别 2、内存基地址和大小 3、总线和桥 4、外设连接 5、中断控制器和中断的使用情况 6、GPIO控制器和GPIO使用情况 7、clock控制器和clock使用情况 它基本就是一棵电路板上的CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核来识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给内核,内核会将这些资源绑定给展开的相应设备。 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离。在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写。引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的"arch/arm/boot/dts/"目录内,比如stmp1a-dk1参考板的板级设备树文件就是"arch/arm/boot/dts/ stm32mp157a-dk1.dts"。这个文件可以通过make dtbs命令编译成二进制的.dtb文件供内核驱动使用。 基于同样的软件分层设计的思想,由于一个SoC可能对应多个machine,如果每个machine的设备树都写成一个完全独立的.dts文件,那么势必相当一些.dts文件有重复的部分,为了解决这个问题,Linux设备树目录把一个SoC公用的部分或者多个machine共同的部分提炼为相应的.dtsi文件。这样每个.dts就只有自己差异的部分,公有的部分只需要"include"相应的.dtsi文件, 这样就是整个设备树的管理更加有序。我这里用Linux4.19.94源码自带的goodix touchscreen触摸芯片为例来分析设备树的使用和移植。这个触摸芯片的设备树节点信息在" Documentation/devicetree/bindings/input/touchscreen/goodix.txt"有详细说明,其驱动源码是" drivers/input/touchscreen/goodix.c"。 ==基础知识介绍== *dts 硬件的相应信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一份例如stm32mp157a-dk1.dts,一般在Linux源码中存在大量的dts文件,对于arm架构可以在arch/arm/boot/dts找到相应的dts,一个dts文件对应一个ARM的machie。 *dtsi 值得一提的是,对于一些相同的dts配置可以抽象到dtsi文件中,然后类似于C语言的方式可以include到dts文件中,对于同一个节点的设置情况,dts中的配置会覆盖dtsi中的配置。 *dtc dtc是编译dts的工具,可以在Ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具; *dtb dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel也需要加入设备树的支持; ==DTS结构== /dts-v1/; / { node1 { a-string-property = "A string"; a-string-list-property = "first string", "second string"; // hex is implied in byte arrays. no '0x' prefix is required a-byte-data-property = [01 23 34 56]; child-node1 { first-child-property; second-child-property = <1>; a-string-property = "Hello, world"; }; child-node2 { }; }; node2 { an-empty-property; a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */ child-node1 { }; }; }; device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,以此加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。root node的node name是确定的,必须是“/”。 也就是说设备树源文件的结构为: *1个root节点”/”; *root节点下面含一系列子节点,“node1” and “node2” *节点node1和下又含有一系列子节点,“child-node1” and “child-node2” *各个节点都有一系列属性 **这些属性可能为空,如an-empty-property **可能为字符串,如a-string-property **可能为字符串树组,如a-string-list-property **可能为Cells(由u32整数组成),如second-child-property ==DTS语法介绍== 了解了基本的device tree的结构后,我们总要把这些结构体现在device tree source code上来。在linux kernel中,扩展名是dts的文件就是描述硬件信息的device tree source file,在dts文件中,一个node被定义成如下格式: [label:] node-name[@unit-address] { [properties definitions] [child nodes] } “[]”表示option,因此可以定义一个只有node name的空节点,label方便在dts文件中引用。 基本数据类型: *text string(以null结束),以双引号括起来,如:string-property = “a string”; *cells 是32位无符号整形数,以尖括号括起来,如:cell-property = <0xbeef 123 0xabcd1234>; *binary data 以方括号括起来,如:binary-property = [0x01 0x23 0x45 0x67]; *不同类型数据可以在同一个属性中存在,以逗号分格,如:mixed-property = “a string”, [0x01 0x23 0x45 0x67],<0x12345678>; *多个字符串组成的列表也使用逗号分格,如:string-list = “red fish”,”blue fish”; ==dts的组成== ===compatible=== 每一个dts文件都是由一个root的根节点组成,内核通过根节点“/”的兼容性即可判断它启动的是什么设备,其代码结构如下 C++ Code / { model = "HQYJ FS-MP1A Discovery Board"; compatible = "st,stm32mp157a-dk1", "st,stm32mp157", "hqyj,fsmp1a"; aliases { ethernet0 = ðernet0; serial0 = &uart4; serial5 = &usart3; }; chosen { stdout-path = "serial0:115200n8"; }; ... ... }; model属性值是,它指定制造商的设备型号。推荐的格式是:“manufacturer,model”,其中manufacturer是一个字符串描述制造商的名称,而型号指定型号。 compatible属性值是,指定了系统的名称,是一个字符串列表,它包含了一个“<制造商>,<型号>”形式的字符串。重要的是要指定一个确切的设备,并且包括制造商的名字,以避免命名空间冲突。 chosen 节点不代表一个真正的设备,但功能与在固件和操作系统间传递数据的地点一样,如根参数,取代以前bootloader的启动参数,控制台的输入输出参数等。 ===#address-cells和#size-cells=== port { #address-cells = <1>; #size-cells = <0>; ltdc_ep0_out: endpoint@0 { reg = <0>; remote-endpoint = <&sii9022_in>; }; }; #address-cells = <1>: 基地址、片选号等绝对起始地址所占字长,单位uint32。 #size-cells = <1>: 长度所占字长,单位uint32。 ===CPU addressing=== 在讨论寻址时,CPU节点代表了最简单的情况。 每个CPU都分配有一个唯一的ID,并且没有与CPU ID相关联的大小。 cpus { #address-cells = <1>; #size-cells = <0>; cpu0: cpu@0 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; clocks = <&rcc CK_MPU>; clock-names = "cpu"; operating-points-v2 = <&cpu0_opp_table>; nvmem-cells = <&part_number_otp>; nvmem-cell-names = "part_number"; }; cpu1: cpu@1 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <1>; clocks = <&rcc CK_MPU>; clock-names = "cpu"; operating-points-v2 = <&cpu0_opp_table>; }; }; 在cpus节点,#address-cells被设置成了1,#size-cells被设置成了0。这是说子reg值是单独的uint32,它用无大小字段表示地址。在此情况下,这两个cpu分配到的地址为0和1。cpu节点的#size-cells是0因为每个cpu只分配到了一个单独的地址。 你仍然需要注意reg值班需要与节点名的值相匹配。按照惯例,如果一个节点有一个reg属性,那么这个节点名称必须包括unit-address,这是reg属性的第一个address值。 ===Memory Mapped Devices=== ===Non Memory Mapped Devices=== ===Ranges (Address Translation)=== ===status=== ===中断映射=== ===特殊节点===
返回至
设备树详解
。
导航菜单
个人工具
登录
命名空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
关于我们
联系我们
资料下载
STM32F103开发板
STM32U575开发板
STM32MP157开发板
Hi3861鸿蒙开发板
HaaS EDU开发板
ESP32开发板
i.MX8M Plus开发板
图书下载
嵌入式系列图书
物联网系列图书
Android系列图书
高校教仪
嵌入式实验室产品
物联网实验室产品
人工智能实验室产品
虚拟仿真实验室产品
行业应用实训室产品
虚拟仿真
嵌入式虚拟仿真平台
物联网虚拟仿真平台
人工智能虚拟仿真
友情链接
华清远见研发中心
元宇宙实验中心
华清远见硬件商城
工具
链入页面
相关更改
特殊页面
页面信息