内核3.x版本之后设备树(device tree)机制

dts 语法学习 3、reg属性 设备的unit-address地址也经常在其对应结点的reg属性中给出。ePAPR标准给出了结点命名的规范: reg #address-cells #size-cells reg: reg的组织形式为reg = <address1 length1 [address2 length2] [address3 length3] … >,其中的每一组address length表明了设备使用的一个地址范围。 #address-cells: 为1个或多个32位的整型(即cell),基地 阅读详情

1.    ARM Device Tree起源

Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pain in the ass”,引发ARM Linux社区的地震,随后ARM社区进行了一系列的重大修正。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。读者有兴趣可以统计下常见的s3c2410、s3c6410等板级目录,代码量在数万行。
社区必须改变这种局面,于是PowerPC等其他体系架构下已经使用的Flattened Device Tree(FDT)进入ARM社区的视野。Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):
  • CPU的数量和类别
  • 内存基地址和大小
  • 总线和桥
  • 外设连接
  • 中断控制器和中断使用情况
  • GPIO控制器和GPIO使用情况
  • Clock控制器和Clock使用情况
它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

2.内核3.x版本之后设备树机制

Based  on  linux  3.10.24  source  code 

参考/documentation/devicetree/Booting-without-of.txt文档

目录

内核3.x版本之后设备树机制 1

一、设备树(Device  Tree)基本概念及作用 3

二、设备树的组成和使用 4

①DTS和DTSI 4

②DTC 4

③DTB 5

④Bootloader 5

三、设备树中dts、dtsi文件的基本语法 5

㈠chosen node 8

㈡aliases node 8

㈢memory node 9

㈣ 其他节点 10

四、DTB相关结构 13

㈠Header 14

㈢字符串块 16

㈣ memory reserve map 16

五、解析DTB的函数及相关数据结构 17

㈠machine_desc结构 17

㈡设备节点结构体 18

㈢属性结构体 19

㈣ uboot下的相关结构体 19

六、DTB加载及解析过程 21

七、OF的API接口 32


一、设备树(Device  Tree)基本概念及作用

在内核源码中,存在大量对板级细节信息描述的代码。这些代码充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目录,对内核而言这些platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data绝大多数纯属垃圾冗余代码。为了解决这一问题,ARM内核版本3.x之后引入了原先在Power PC等其他体系架构已经使用的Flattened Device Tree。

“A data structure by which bootloaders pass hardware layout to Linux in a device-independent manner, simplifying hardware probing.”开源文档中对设备树的描述是,一种描述硬件资源的数据结构,它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立。

Device Tree可以描述的信息包括CPU的数量和类别、内存基地址和大小、总线和桥、外设连接、中断控制器和中断使用情况、GPIO控制器和GPIO使用情况、Clock控制器和Clock使用情况。

另外,设备树对于可热插拔的热备不进行具体描述,它只描述用于控制该热插拔设备的控制器。

设备树的主要优势:对于同一SOC的不同主板,只需更换设备树文件.dtb即可实现不同主板的无差异支持,而无需更换内核文件。

注:要使得3.x之后的内核支持使用设备树,除了内核编译时需要打开相对应的选项外,bootloader也需要支持将设备树的数据结构传给内核。

二、设备树的组成和使用

设备树包含DTC(device tree compiler),DTS(device tree source和DTB(device tree blob)。其对应关系如图1-1所示:



图1-1 DTS、DTC、DTB之间的关系

①DTS和DTSI

.dts文件是一种ASCII文本对Device Tree的描述,放置在内核的/arch/arm/boot/dts目录。一般而言,一个.dts文件对应一个ARM的machine。

由于一个SOC可能有多个不同的电路板,而每个电路板拥有一个 .dts。这些dts势必会存在许多共同部分,为了减少代码的冗余,设备树将这些共同部分提炼保存在.dtsi文件中,供不同的dts共同使用。.dtsi的使用方法,类似于C语言的头文件,在dts文件中需要进行include .dtsi文件。当然,dtsi本身也支持include 另一个dtsi文件。

②DTC

DTC为编译工具,它可以将.dts文件编译成.dtb文件。DTC的源码位于内核的scripts/dtc目录,内核选中CONFIG_OF,编译内核的时候,主机可执行程序DTC就会被编译出来。 即scripts/dtc/Makefile中

hostprogs-y := dtc

always := $(hostprogs-y) 

在内核的arch/arm/boot/dts/Makefile中,若选中某种SOC,则与其对应相关的所有dtb文件都将编译出来。在linux下,make dtbs可单独编译dtb。以下截取了TEGRA平台的一部分。

ifeq ($(CONFIG_OF),y)

dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \

tegra30-beaver.dtb \

tegra114-dalmore.dtb \

tegra124-ardbeg.dtb 

③DTB

DTC编译.dts生成的二进制文件(.dtb),bootloader在引导内核时,会预先读取.dtb到内存,进而由内核解析。

④Bootloader

Bootloader需要将设备树在内存中的地址传给内核。在ARM中通过bootm或bootz命令来进行传递。bootm [kernel_addr] [initrd_address] [dtb_address],其中kernel_addr为内核镜像的地址,initrd为initrd的地址,dtb_address为dtb所在的地址。若initrd_address为空,则用“-”来代替。

三、设备树中dts、dtsi文件的基本语法

DTS的基本语法范例,如图3-1 所示。

它包括一系列节点,以及描述节点的属性。

“/”为root节点。在一个.dts文件中,有且仅有一个root节点;在root节点下有“node1”,“node2”子节点,称root为“node1”和“node2”的parent节点,除了root节点外,每个节点有且仅有一个parent;其中子节点node1下还存在子节点“child-nodel1”和“child-node2”。

注:如果看过内核/arch/arm/boot/dts目录的读者看到这可能有一个疑问。在每个.dsti和.dts中都会存在一个“/”根节点,那么如果在一个设备树文件中include一个.dtsi文件,那么岂不是存在多个“/”根节点了么。其实不然,编译器DTC在对.dts进行编译生成dtb时,会对node进行合并操作,最终生成的dtb只有一个root node。Dtc会进行合并操作这一点从属性上也可以得到验证。这个稍后做讲解。

在节点的{}里面是描述该节点的属性(property),即设备的特性。它的值是多样化的:

1.它可以是字符串string,如①;也可能是字符串数组string-list,如②

2.它也可以是32 bit unsigned integers,如cell⑧,用<>表示

3.它也可以是binary data,如③,用[]表示

4.它也可能是空,如⑦


图3-1  DTS的基本语法范例

在/arch/arm/boot/dts/目录中有一个文件skeleton.dtsi,该文件为各ARM vendor共用的一些硬件定义信息。以下为skeleton.dtsi的全部内容。

/ {

#address-cells = <1>;

#size-cells = <1>;

chosen { };

aliases { };

memory { device_type = "memory"; reg = <0 0="">; };

};

如上,属性# address-cells的值为1,它代表以“/”根节点为parent的子节点中,reg属性中存在一个address值;#size-cells的值为1,它代表以“\” 根节点为parent的子节点中,reg属性中存在一个size值。即父节点的# address-cells和#size-cells决定了子节点的address和size的长度;Reg的组织形式为reg = 

下面列举例子,对一些典型节点进行具体描述。

㈠chosen node

chosen {

bootargs = "tegraid=40.0.0.00.00 vmalloc=256M video=tegrafb console=ttyS0,115200n8 earlyprintk";

};

chosen node 主要用来描述由系统指定的runtime parameter,它并没有描述任何硬件设备节点信息。原先通过tag list传递的一些linux kernel运行的参数,可以通过chosen节点来传递。如command line可以通过bootargs这个property来传递。如果存在chosen node,它的parent节点必须为“/”根节点。

㈡aliases node

aliases {

i2c6 = &pca9546_i2c0;

i2c7 = &pca9546_i2c1;

i2c8 = &pca9546_i2c2;

i2c9 = &pca9546_i2c3;

};

aliases node用来定义别名,类似C++中引用。上面是一个在.dtsi中的典型应用,当使用i2c6时,也即使用pca9546_i2c0,使得引用节点变得简单方便。例:当.dts  include 该.dtsi时,将i2c6的status属性赋值为okay,则表明该主板上的pca9546_i2c0处于enable状态;反之,status赋值为disabled,则表明该主板上的pca9546_i2c0处于disenable状态。如下是引用的具体例子:

&i2c6 {

status = "okay";

};

㈢memory node

memory {

device_type = "memory";

reg = <0x00000000 0x20000000="">; /* 512 MB */

};

对于memory node,device_type必须为memory,由之前的描述可以知道该memory node是以0x00000000为起始地址,以0x20000000为结束地址的512MB的空间。

一般而言,在.dts中不对memory进行描述,而是通过bootargs中类似521M@0x00000000的方式传递给内核。

㈣ 其他节点

由于其他设备节点依据属性进行描述,具有类似的形式。接下来的部分主要分析各种属性的含义及作用,并结合相关的例子进行阐述。

㈠ Reg属性

在device node 中,reg是描述memory-mapped IO register的offset和length。子节点的reg属性address和length长度取决于父节点对应的#address-cells和#size-cells的值。例:

在上述的aips节点中,存在子节点spda。spda中的中reg为<0x70000000 0x40000 >,其0x700000000为address,0x40000为size。这一点在图3-1下有作介绍。

这里补充的一点是:

设备节点的名称格式node-name@unit-address,节点名称用node-name唯一标识,为一个ASCII字符串。其中@unit-address为可选项,可以不作描述。unit-address的具体格式和设备挂载在哪个bus上相关。如:cpu的unit-address从0开始编址,以此加1;本例中,aips为0x70000000。

㈡ compatible属性

在①中,compatible属性为string list,用来将设备匹配对应的driver驱动,优先级为从左向右。本例中spba的驱动优先考虑“fsl,aips-bus”驱动;若没有“fsl,aips-bus”驱动,则用字符串“simple-bus”来继续寻找合适的驱动。即compatible实现了原先内核版本3.x之前,platform_device中.name的功能,至于具体的实现方法,本文后面会做讲解。

注:对于“/”root节点,它也存在compatible属性,用来匹配machine type。具体说明将在后面给出。

㈢ interrupts属性

设备节点通过interrupt-parent来指定它所依附的中断控制器,当节点没有指定interrupt-parent时,则从parent节点中继承。上面例子中,root节点的interrupt-parent = <&mic>。这里使用了引用,即mic引用了②中的inrerrupt-controller @40008000;root节点的子节点并没有指定interrupt-controller,如ahb、fab,它们均使用从根节点继承过来的mic,即位于0x40008000的中断控制器。

若子节点使用到中断(中断号、触发方法等等),则需用interrupt属性来指定,该属性的数值长度受中断控制器中#inrerrupt-controller值③控制,即interrupt属性<>中数值的个数为#inrerrupt-controller的值;本例中#inrerrupt-controller=<2>,因而④中interrupts的值为<0x3d 0="">形式,具体每个数值的含义由驱动实现决定。

㈣ ranges属性

ranges属性为地址转换表,这在pcie中使用较为常见,它表明了该设备在到parent节点中所对用的地址映射关系。ranges格式长度受当前节点#address-cell、parent节点#address-cells、当前节点#size-cell所控制。顺序为ranges=<前节点#address-cell, parent节点#address-cells , 当前节点#size-cell。在本例中,当前节点#address-cell=<1>,对应于⑤中的第一个0x20000000;parent节点#address-cells=<1>,对应于⑤中的第二个0x20000000;当前节点#size-cell=<1>,对应于⑤中的0x30000000。即ahb0节点所占空间从0x20000000地址开始,对应于父节点的0x20000000地址开始的0x30000000地址空间大小。

注:对于相同名称的节点,dtc会根据定义的先后顺序进行合并,其相同属性,取后定义的那个。

四、DTB相关结构

本节讲下.dts编译生成的dtb文件,其布局结构。

DTB由三部分组成:头(Header)、结构块(device-tree structure)、字符串块(string block)。下面将详细介绍这三部分的内容。

㈠Header

在\kernel\include\linux\of_fdt.h文件中有相关定义


㈡ device-tree structure


设备树结构块是一个线性化的结构体,是设备树的主体,以节点的形式保存了主板上的设备信息。

在结构块中,以宏OF_DT_BEGIN_NODE标志一个节点的开始,以宏OF_DT_END_NODE标识一个节点的结束,整个结构块以宏OF_DT_END (0x00000009)结束。在\kernel\include\linux\of_fdt.h中有相关定义,我们把这些宏称之为token。

(1)FDT_BEGIN_NODE (0x00000001)。该token描述了一个node的开始位置,紧挨着该token的就是node name(包括unit address)

(2)FDT_END_NODE (0x00000002)。该token描述了一个node的结束位置。

(3)FDT_PROP (0x00000003)。该token描述了一个property的开始位置,该token之后是两个u32的数据,分别是length和name offset。length表示该property value data的size。name offset表示该属性字符串在device tree strings block的偏移值。length和name offset之后就是长度为length具体的属性值数据。

(4)FDT_NOP (0x00000004)。

(5)FDT_END (0x00000009)。该token标识了一个DTB的结束位置。

一个节点的结构如下:

(1)节点开始标志:一般为OF_DT_BEGIN_NODE(0x00000001)。

(2)节点路径或者节点的单元名(version<3以节点路径表示,version>=0x10以节点单元名表示)

(3)填充字段(对齐到四字节)

(4)节点属性。每个属性以宏OF_DT_PROP(0x00000003)开始,后面依次为属性值的字节长度(4字节)、属性名称在字符串块中的偏移量(4字节)、属性值和填充(对齐到四字节)。

(5)如果存在子节点,则定义子节点。

(6)节点结束标志OF_DT_END_NODE(0x00000002)。

㈢字符串块

通过节点的定义知道节点都有若干属性,而不同的节点的属性又有大量相同的属性名称,因此将这些属性名称提取出一张表,当节点需要应用某个属性名称时,直接在属性名字段保存该属性名称在字符串块中的偏移量。

㈣ memory reserve map

这个区域包括了若干的reserve memory描述符。每个reserve memory描述符是由address和size组成。其中address和size都是用U64来描述。

有些系统,我们也许会保留一些memory有特殊用途(例如DTB或者initrd image),或者在有些DSP+ARM的SOC platform上,有些memory被保留用于ARM和DSP进行信息交互。这些保留内存不会进入内存管理系统。

五、解析DTB的函数及相关数据结构

㈠machine_desc结构

内核将机器信息记录为machine_desc结构体(该定义在/arch/arm/include/asm/mach/arch.h),并保存在_arch_info_begin到_arch_info_end之间(_arch_info_begin,_arch_info_end为虚拟地址,是编译内核时指定的,此时mmu还未进行初始化。它其实通过汇编完成地址偏移操作)

machine_desc结构体用宏MACHINE_START进行定义,一般在/arch/arm/子目录,与板级相关的文件中进行成员函数及变量的赋值。由linker将machine_desc聚集在.arch.info.init节区形成列表。

bootloader引导内核时,ARM寄存器r2会将.dtb的首地址传给内核,内核根据该地址,解析.dtb中根节点的compatible属性,将该属性与内核中预先定义machine_desc结构体的dt_compat成员做匹配,得到最匹配的一个machine_desc。

在代码中,内核通过在start_kernel->setup_arch中调用setup_machine_fdt来实现上述功能,该函数的具体实现可参见/arch/arm/kernel/devtree.c。 

㈡设备节点结构体

1.

记录节点信息的结构体。.dtb经过解析之后将以device_node列表的形式存储节点信息。

㈢属性结构体

device_node结构体中的成员结构体,用于描述节点属性信息。

㈣ uboot下的相关结构体

首先我们看下uboot用于记录os、initrd、fdt信息的数据结构bootm_headers,其定义在/include/image.h中,这边截取了其中与dtb相关的一小部分。

fit_hdr_fdt指向DTB设备树镜像的头。

lmb为uboot下的一种内存管理机制,全称为logical memory blocks。用于管理镜像的内存。lmb所记录的内存信息最终会传递给kernel。这里对lmb不做展开描述。在/include/lmb.h和/lib/lmb.c中有对lmb的接口和定义的具体描述。有兴趣的读者可以看下,所包含的代码量不多。

六、DTB加载及解析过程

先从uboot里的do_bootm出发,根据之前描述,DTB在内存中的地址通过bootm命令进行传递。在bootm中,它会根据所传进来的DTB地址,对DTB所在内存做一系列操作,为内核解析DTB提供保证。上图为对应的函数调用关系图。

在do_bootm中,主要调用函数为do_bootm_states,第四个参数为bootm所要处理的阶段和状态。 

在do_bootm_states中,bootm_start会对lmb进行初始化操作,lmb所管理的物理内存块有三种方式获取。起始地址,优先级从上往下:

1. 环境变量“bootm_low”

2. 宏CONFIG_SYS_SDRAM_BASE(在tegra124中为0x80000000)

3. gd->bd->bi_dram[0].start

大小:

1. 环境变量“bootm_size”

2. gd->bd->bi_dram[0].size

经过初始化之后,这块内存就归lmb所管辖。接着,调用bootm_find_os进行kernel镜像的相关操作,这里不具体阐述。

还记得之前讲过bootm的三个参数么,第一个参数内核地址已经被bootm_find_os处理,而接下来的两个参数会在bootm_find_other中执行操作。

首先,bootm_find_other根据第二个参数找到ramdisk的地址,得到ramdisk的镜像;然后根据第三个参数得到DTB镜像,同检查kernel和ramdisk镜像一样,检查DTB镜像也会进行一系列的校验工作,如果校验错误,将无法正常启动内核。另外,uboot在确认DTB镜像无误之后,会将该地址保存在环境变量“fdtaddr”中。

接着,uboot会把DTB镜像reload一次,使得DTB镜像所在的物理内存归lmb所管理:①boot_fdt_add_mem_rsv_regions会将原先的内存DTB镜像所在的内存置为reserve,保证该段内存不会被其他非法使用,保证接下来的reload数据是正确的;②boot_relocate_fdt会在bootmap区域中申请一块未被使用的内存,接着将DTB镜像内容复制到这块区域(即归lmb所管理的区域)

注:若环境变量中,指定“fdt_high”参数,则会根据该值,调用lmb_alloc_base函数来分配DTB镜像reload的地址空间。若分配失败,则会停止bootm操作。因而,不建议设置fdt_high参数。

接下来,do_bootm会根据内核的类型调用对应的启动函数。与linux对应的是do_bootm_linux。

① boot_prep_linux

为启动后的kernel准备参数

② boot_jump_linux

以上是boot_jump_linux的片段代码,可以看出:若使用DTB,则原先用来存储ATAG的寄存器R2,将会用来存储.dtb镜像地址。

boot_jump_linux最后将调用kernel_entry,将.dtb镜像地址传给内核。


下面我们来看下内核的处理部分:

在arch/arm/kernel/head.S中,有这样一段:

_vet_atags定义在/arch/arm/kernel/head-common.S中,它主要对DTB镜像做了一个简单的校验。

真正解析处理dbt的开始部分,是setup_arch->setup_machine_fdt。这部分的处理在第五部分的machine_mdesc中有提及。

如图,是setup_machine_fdt中的解析过程。

解析chosen节点将对boot_command_line进行初始化。

解析根节点的{size,address}将对dt_root_size_cells,dt_root_addr_cells进行初始化。为之后解析memory等其他节点提供依据。

解析memory节点,将会把节点中描述的内存,加入memory的bank。为之后的内存初始化提供条件。


解析设备树在函数unflatten_device_tree中完成,它将.dtb解析成device_node结构(第五部分有其定义),并构成单项链表,以供OF的API接口使用。

下面主要结合代码分析:/drivers/of/fdt.c


















总的归纳为:

① kernel入口处获取到uboot传过来的.dtb镜像的基地址

② 通过early_init_dt_scan()函数来获取kernel初始化时需要的bootargs和cmd_line等系统引导参数。

③ 调用unflatten_device_tree函数来解析dtb文件,构建一个由device_node结构连接而成的单向链表,并使用全局变量of_allnodes保存这个链表的头指针。

④ 内核调用OF的API接口,获取of_allnodes链表信息来初始化内核其他子系统、设备等。


七、OF的API接口

OF的接口函数在/drivers/of/目录下,有of_i2c.c、of_mdio.c、of_mtd.c、Adress.c等等

这里将列出几个常用的API接口。


1. 用来查找在dtb中的根节点

unsigned long __init of_get_flat_dt_root(void)


2. 根据deice_node结构的full_name参数,在全局链表of_allnodes中,查找合适的device_node

struct device_node *of_find_node_by_path(const char *path)

例如:

struct device_node *cpus;

cpus=of_find_node_by_path("/cpus");


3. 若from=NULL,则在全局链表of_allnodes中根据name查找合适的device_node

struct device_node *of_find_node_by_name(struct device_node *from,const char *name)

例如:

struct device_node *np;

np = of_find_node_by_name(NULL,"firewire");


4. 根据设备类型查找相应的device_node

struct device_node *of_find_node_by_type(struct device_node *from,const char *type)

例如:

struct device_node *tsi_pci;

tsi_pci= of_find_node_by_type(NULL,"pci");


5. 根据compatible字符串查找device_node

struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible)


6. 根据节点属性的name查找device_node

struct device_node *of_find_node_with_property(struct device_node *from,const char *prop_name)


7. 根据phandle查找device_node

struct device_node *of_find_node_by_phandle(phandle handle)


8. 根据alias的name获得设备id号

int of_alias_get_id(struct device_node *np, const char *stem)


9. device node计数增加/减少

struct device_node *of_node_get(struct device_node *node)

void of_node_put(struct device_node *node)


10. 根据property结构的name参数,在指定的device node中查找合适的property

struct property *of_find_property(const struct device_node *np,const char *name,int *lenp)


11. 根据property结构的name参数,返回该属性的属性值

const void *of_get_property(const struct device_node *np, const char *name,int *lenp)


12. 根据compat参数与device node的compatible匹配,返回匹配度

int of_device_is_compatible(const struct device_node *device,const char *compat)


13. 获得父节点的device node

struct device_node *of_get_parent(const struct device_node *node)


14. 将matches数组中of_device_id结构的name和type与device node的compatible和type匹配,返回匹配度最高的of_device_id结构

const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)


15. 根据属性名propname,读出属性值中的第index个u32数值给out_value

int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index, u32 *out_value)


16. 根据属性名propname,读出该属性的数组中sz个属性值给out_values

int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)

int of_property_read_u16_array(const struct device_node *np,const char *propname, u16 *out_values, size_t sz)

int of_property_read_u32_array(const struct device_node *np,const char *propname, u32 *out_values,size_t sz)


17. 根据属性名propname,读出该属性的u64属性值

int of_property_read_u64(const struct device_node *np, const char *propname,u64 *out_value)


18. 根据属性名propname,读出该属性的字符串属性值

int of_property_read_string(struct device_node *np, const char *propname,const char **out_string)


19. 根据属性名propname,读出该字符串属性值数组中的第index个字符串

int of_property_read_string_index(struct device_node *np, const char *propname,int index, const char **output)


20. 读取属性名propname中,字符串属性值的个数

int of_property_count_strings(struct device_node *np, const char *propname)


21. 读取该设备的第index个irq号

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)


22. 读取该设备的第index个irq号,并填充一个irq资源结构体

int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)


23. 获取该设备的irq个数

int of_irq_count(struct device_node *dev)


24. 获取设备寄存器地址,并填充寄存器资源结构体

int of_address_to_resource(struct device_node *dev, int index,struct resource *r)

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,unsigned int *flags)


25. 获取经过映射的寄存器虚拟地址

void __iomem *of_iomap(struct device_node *np, int index)


24. 根据device_node查找返回该设备对应的platform_device结构

struct platform_device *of_find_device_by_node(struct device_node *np)


25. 根据device node,bus id以及父节点创建该设备的platform_device结构

struct platform_device *of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)

static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,

void *platform_data,struct device *parent)


26. 遍历of_allnodes中的节点挂接到of_platform_bus_type总线上,由于此时of_platform_bus_type总线上还没有驱动,所以此时不进行匹配

int of_platform_bus_probe(struct device_node *root,const struct of_device_id *matches,struct device *parent)


设备树dts语法格式 设备树就是平台总线中的平台设备的衍生,是用于表述硬件设备资源的,对于ARM平台,设备树文件存放在arch/arm/boot/dts下,绑定文档存在Documentation/devicetree/bindings下。 我把jz2440_LED——设备树之点亮LED灯中的设备树文件拷贝过来,进行简单的介绍设备树的格式, /dts-v1/; / { model = "SMDK24440"; compatible = "samsung,smdk2440"; #address-cel... 阅读详情

相关推荐

Device Tree Overlays:”插件“设备树

Device Tree Overlays:”插件“设备树 传统设备树 批量管理硬件资源,机制僵化 ”插件“设备树 模块化管理硬件资源,灵活定制 使用前提 内核配置 CONFIG_OF_OVERLAY = y CONFIG_OF_CONFIGFS = y 挂载ConfigFS mount x /sys/kernel/config -t configfs 案例说明 设备树:foo.dts / { compatible = "corp,foo"; /* On chip perip

十七阿哥的博客 4388

Linux I2C framework(3)_I2C consumer

转载地址:http://www.wowotech.net/comm/i2c_consumer.html 1. 前言 本文从I2C consumer的角度,介绍怎么在linux中,利用I2C framework提供的接口,编写I2C slave device的驱动程序。 2. 两种设备形态 嵌入式系统中,I2C总线上连接的slave device,有两种形态,如下: 图片1 I2C

kunkliu的博客 837

【嵌入式Linux驱动开发】七、驱动开发的利器 - 设备树的闪亮登场

受身无间者永远不死,寿长乃无间地狱中之大劫。 上一节在介绍总线设备驱动模型时,提到platform平台当修改引脚时,设备端的代码需要重新编译生成platform_device结构体,同时过多的设备对应的.c文件也会造成过多的冗余代码。而本节将迎来设备树,继续解决这一难题!

悟已往之不谏 知来者之可追 2039

android dtb文件位置_内核3.x版本之后设备树机制 ( dtb二进制文件结构,header,device-tree 结构,树形结构,machine结构 , dtb加载和解析,函数调用 , ...

---------------------------------| 欢迎转载;转载请注明,谢谢 |---------------------------------Basedonlinux3.10.24sourcecode参考/documentation/devicetree/Booting-without-of.txt文档1.设备树(DeviceTree)基本概念及作用...

weixin_31101725的博客 1375

避开封号风险!wxauto+Claude API实现微信智能客服的合规方案

本文详细介绍了如何利用wxauto和Claude API构建合规的微信智能客服系统,避免封号风险。通过技术选型对比、防封策略设计及大模型接入实践,为企业提供了一套安全高效的解决方案,特别适合中小企业在微信生态中部署AI客服。

sql99的博客 448

在CoppeliaSim里实现一个最简单的强化学习

前言 上一篇文章中介绍了CoppeliaSim的一些基本知识和一个简单的用python去控制CoppeliaSim里面四旋翼无人机运动的一个例子。文章链接 :https://blog.csdn.net/qq_37051669/article/details/115324851 本文将继续介绍如何利用CoppeliaSim的物理环境去实现一个最简单的强化学习。 如何实现强化学习 强化学习(Reinforcementlearning)是机器学习中的一个领域,强调如何基于环境而行动,以取得最大化的预期利.

qq_37051669的博客 3765

内核3.x版本之后设备树机制

原文地址:https://blog.csdn.net/machiner1/article/details/47805069   内核3.x版本之后设备树机制 Based  on  linux  3.10.24  source  code  参考/documentation/devicetree/Booting-without-of.txt文档 目录 内核3.x版本之后设备树机制 1 ...

爱自在的专栏 274

I2C总线原理及总线信号的实现

I2C总线是一种多主机总线,连接IIC总线上的器件分为主机和从机,主机有权发起和结束一次通信,而从机只能被主机呼叫;当总线上有多个主机同时启用总线时,I2C也具备冲突检测和仲裁的功能来防止错误产生;每个连接到IIC总线上的器件都有一个唯一的地址(7bit),且每个器件都可以作为主机也可以作为从机(同一时刻只能有一个主机),总线上的器件增加和删除不影响其他器件正常工作;I2C总线在通信时总线上发送数据的器件为发送器,接收数据的器件为接收器;主要用于近距离(抗干扰能力稍弱),低速的芯片之间的通信(传输视频,带宽

YLG_lin的博客 3943

内核3.x版本之后设备树机制 ( dtb二进制文件结构,header,device-tree 结构,树形结构,machine结构 , dtb加载和解析,函数调用 , aliase 节点 &i2c6...

转载于 :http://rick_stone.leanote.com/post/%E5%86%85%E6%A0%B83.x%E7%89%88%E6%9C%AC%E4%B9%8B%E5%90%8E%E8%AE%BE%E5%A4%87%E6%A0%91%E6%9C%BA%E5%88%B6 内核3.x版本之后设备树机制 dtb2016-02-13 22:47:00 467...

weixin_30546189的博客 603

基于PI双闭环解耦控制的三相SVPWM电压型逆变器(1)--数学模型

三相电压型逆变器、双PI控制、SVPWM、解耦

weixin_58670090的博客 1万+

【CubeMX】STM32G474 HRTIM 死区时间与互补PWM实战解析

本文深入解析STM32G474的HRTIM高分辨率定时器在互补PWM生成与死区时间配置中的应用。通过CubeMX工具详细演示时钟配置、单路PWM基础、互补输出与死区时间设置,并结合逆变器等电力电子实战案例,帮助开发者避免直通风险,优化系统性能。

efc12345678的博客 746

内核3.x版本之后设备树机制 ( dtb二进制文件结构,header,device-tree 结构,树形结构,machine结构 , dtb加载和解析,函数调用 , aliase 节点 &i2c6{.

https://www.cnblogs.com/tureno/articles/6399782.html

zhuzaijava的专栏 335

模拟波束赋形 vs 数字波束赋形:5G天线设计中的成本与性能权衡

本文深入剖析了5G天线设计中模拟波束赋形与数字波束赋形的核心差异,重点探讨了二者在硬件成本、功耗、网络覆盖能力和频谱效率等方面的权衡。文章指出,模拟方案成本低但灵活性有限,数字方案性能强大但代价高昂,而混合波束赋形已成为主流折中方案。决策需紧密结合具体的部署场景、性能要求和总拥有成本进行综合考量。

weixin_28432777的博客 840

Linux 内核设备树(Device Tree)与内核代码匹配关系详解

设备树(Device Tree, DT)是一种描述硬件信息的数据结构,主要用于无固化 BIOS/ACPI 的嵌入式系统,如 ARM 体系结构。Linux 内核通过解析设备树,获取硬件拓扑信息,并在驱动程序中进行匹配,使驱动能够正确初始化设备。设备树的主要作用描述 SoC(片上系统)的硬件资源,如 CPU、内存、总线、外设等。使内核代码与硬件解耦,增强可移植性。提供统一的硬件抽象层,支持不同的 SoC。

Interview_TC的博客 1953

避坑指南:SAP CO模块维护成本控制范围的5个常见错误及解决方法

本文深入剖析了SAP CO模块中维护成本控制范围时最易犯的5个常见错误,包括货币参数配置不当、标准层次结构缺失、财政年度变式不一致、功能激活遗漏及集成参数设置错误。重点针对事务码OKKP的配置,提供了详细的排查步骤与实战解决方案,帮助顾问有效规避陷阱,确保成本核算体系稳定运行。

stone的博客 234

GEE土地分类:土地分类精度评定和分类后影像进行(Kmeans,Gmeans,SNIC (Simple Non-Iterative Clustering)聚类分析和滤波(focal_mode)分析

使用聚类分析和滤波分析来进一步处理土地分类后的影像数据。聚类分析可以帮助您识别影像中的相似区域。您可以使用聚类算法,如K均值聚类或层次聚类,将像素分组到具有相似像素值的群集中。这可以帮助您更好地理解图像中的空间模式和结构,并可能揭示有用的信息。滤波分析可以帮助您平滑图像并去除噪声。常见的滤波器包括中值滤波器和高斯滤波器。这些滤波器可以帮助您消除图像中的随机变化,并使其更易于解释和分析。

此星光明博客 2516

Linux 设备树(Device Tree)概览

本文是一份系统化的 Linux 设备树(Device Tree)学习与实践指南,覆盖从硬件描述思想、语法规范、内核解析机制到驱动开发实战的完整知识体系。

smallerxuan的博客 6955

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Linux设备树(Device Tree)机制

目录 1. 设备树(DeviceTree)基本概念及作用 2. 设备树的组成和使用 2.1. DTS和DTSI 2.2. DTC 2.3. DTB 2.4. Bootloader 3. 设备树中dts、dtsi文件的基本语法 3.1. chosennode 3.2. aliasesnode 3.3. memorynode 3.4. ...

Yannick Jiang 的专栏 2911

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Linux设备树(Device Tree)

在Linux3.x版本下,Linux内核中ARM架构的板级信息大量放置在 arch/arm/mach-xxx 和 arch/arm/plat-xxx 文件夹下,例如platform设备、resource、spi_board_info以及各种硬件的platform_data,这些信息对Linux内核来说无关紧要,会造成大量的冗余编码,导致ARM的merge工作量较大。当采用设备树(device tree)之后,许多硬件的细节可以直接透过设备树传递给Linux内核,大大减少了Linux内核的冗余代码量。....

Eddy的博客 4635

【Linux 驱动开发】Linux设备树 (Device Tree) 深度解析

本文深入解析Linux设备树(Device Tree)的核心概念与应用。从设备树的起源与发展入手,详细介绍了其语法结构(节点、属性、标签与引用)、编译加载流程,并通过实例展示典型嵌入式开发板的设备树配置。文章还阐述了驱动与设备树的交互机制,包括匹配规则和常用API,最后分享了设备树覆盖、运行时修改等高级技巧。设备树实现了硬件描述与内核源码的解耦,是Linux内核支持多样化硬件平台的重要机制。

love131452098的博客 1058

linux Linux 3.x的设备树(Device Tree) dts 介绍

在http://blog.csdn.net/21cnbao/article/details/8457546 进行整理修改,感谢此博主。 1.  1.1. 简介   Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pain in the ass”,引发ARM Linux社区的地震,随后ARM

kylin_fire_zeng的专栏 1万+

linux内核机制之设备树

1. 设备树(Device  Tree)基本概念及作用 在内核源码中,存在大量对板级细节信息描述的代码。这些代码充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目录,对内核而言这些platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data绝大多数纯属垃圾冗余代码。为了解决这一问题,ARM内核版本3.x之后引入了原先在Power PC等其他体系架构已经使用的Flatte

wll1228的博客 4192
上一篇: HID 描述符(二)——报告描述符
下一篇: Linux资源控制-CPU和内存
wdsfup
博客等级 码龄20年 31粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值