Linux设备树详解概述.docx

上传人:b****1 文档编号:15210166 上传时间:2023-07-02 格式:DOCX 页数:130 大小:48.67KB
下载 相关 举报
Linux设备树详解概述.docx_第1页
第1页 / 共130页
Linux设备树详解概述.docx_第2页
第2页 / 共130页
Linux设备树详解概述.docx_第3页
第3页 / 共130页
Linux设备树详解概述.docx_第4页
第4页 / 共130页
Linux设备树详解概述.docx_第5页
第5页 / 共130页
Linux设备树详解概述.docx_第6页
第6页 / 共130页
Linux设备树详解概述.docx_第7页
第7页 / 共130页
Linux设备树详解概述.docx_第8页
第8页 / 共130页
Linux设备树详解概述.docx_第9页
第9页 / 共130页
Linux设备树详解概述.docx_第10页
第10页 / 共130页
Linux设备树详解概述.docx_第11页
第11页 / 共130页
Linux设备树详解概述.docx_第12页
第12页 / 共130页
Linux设备树详解概述.docx_第13页
第13页 / 共130页
Linux设备树详解概述.docx_第14页
第14页 / 共130页
Linux设备树详解概述.docx_第15页
第15页 / 共130页
Linux设备树详解概述.docx_第16页
第16页 / 共130页
Linux设备树详解概述.docx_第17页
第17页 / 共130页
Linux设备树详解概述.docx_第18页
第18页 / 共130页
Linux设备树详解概述.docx_第19页
第19页 / 共130页
Linux设备树详解概述.docx_第20页
第20页 / 共130页
亲,该文档总共130页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Linux设备树详解概述.docx

《Linux设备树详解概述.docx》由会员分享,可在线阅读,更多相关《Linux设备树详解概述.docx(130页珍藏版)》请在冰点文库上搜索。

Linux设备树详解概述.docx

Linux设备树详解概述

Linux设备树详解

概述

}设备树(DeviceTree)是一种描述硬件的数据结构,在操作系统(OS)引导

阶段进行设备初始化的时候,数据结构中的硬件信息被检测并传递给操作系统

最早诞生于OpenFirmware,FlattenedDeviceTree(FDT)格式标准。

}dts文件(DeviceTreeSource,dts)是以ASCII文本形式描述设备树内容。

}dtb文件是二进制格式,编译工具为:

DeviceTreeCompiler(DTC)。

}2011年被引入ARMLinux内核。

ARMLinux设备树描述了内核的软/硬件信息。

节点(node)和属性(property)

}节点用以归类描述一个硬件信息或是软件信息(好比文件系统的目录)

}节点内描述了一个或多个属性,属性是键值对(key/value),描述具体的

软/硬信息。

为什么ARMLinux社区会引入设备树呢?

}主要是想解决ARMLinux内核代码冗余的问题。

学习参考

内核源码目录Documentation\devicetree设备树范例的说明文档

内核源码drivers/of目录下是设备树操作实现源码

内核源码include/linux目录下的of_xxx.h是设备树的头

DTS描述键值对的语法:

}1、字符串信息

}2、32bits无符号整型数组信息

}3、二进制数数组

}4、混和形式

}5、字符串哈希表

/dts-v1/;

#include""//此设备树依赖于文件

#include//gpio引脚配置文件

/{//根节点rootnode

model="FriendlyARMTINY4412boardbasedonExynos4412";

compatible="friendlyarm,tiny4412","samsung,exynos4412","samsung,exynos4";

chosen{

stdout-path=&serial_0;

};

节点语法规范说明

节点名:

语法:

[@]

规范:

名字是ASCII字符串

(字母、数字、"-"、等等构成)

最长可以是31个字符

一般的,应该以设备类型命名

unit-address一般的是设备地址

/*****示例*****/

/{

serial@101F0000{

……

};

gpio@101F3000{

……

};

interrupt-controller@{

……

};

spi@{

…….

};

external-bus{

……

};

i2c@1,0{

…….

rtc@58{

......

};

};

};

};

节点名及节点路径

/{

dm9000{

};

};

节点名:

dm9000

节点路径:

/dm9000

节点别名(节点引用)

为了解决节点路径名过长的问题,引入了节点别名的概念,可以引用到一个全路径的节点

/{

aliases{

demo=&demo0;

};

demo:

demo0@{

};

};

节点名:

demo0

节点路径:

/demo0@

节点别名:

demo(等价/demo0@)

/**********************************/

引用语法范例1:

&demo{

};

引用语法范例2:

/{

reference-node{

property=<&demo>;

};

};

};

合并节点内容

一般的,一个硬件设备的部分信息不会变化,但是部分信息是可能会变化的,就出现了节点内容合并。

即:

先编写好节点,仅仅描述部分属性值;使用者后加一部分属性值。

在同级路径下,节点名相同的“两个”节点实际是一个节点。

/*参考板的已经编写好的node节点*/

/{

node{

property=value;

};

};

/*移植者添加的节点*/

/{

node{

property2=value;

};

};

/***合并后的节点内容***/

/{

node{

property2=value;

};

};

替换节点内容

一般的,一个硬件设备的部分属性信息可能会变化,但是设备树里面已经描述了所有的属性值,使用者可以添加已有的属性值,以替换原有的属性值,就出现了节点内容替换。

在同级路径下,节点名相同的“两个”节点实际是一个节点。

/*参考板的已经编写好的node节点*/

/{

node{

property=value;

status=”disabled”;/{

};node{

};property=value;

⇨status=”okay”;

/*移植者添加的node节点*/};

/{};

node{

status=”okay”;

};

};

引用节点内容

一般的,一个设备可能会使用到别的节点的内容,可以通过节点的别名来引用到其内容。

引用的目的可能是合并两个节点的内容、替换部分内容、或是使用部分内容。

/*参考板的已经编写好的node节点*/

/{

node:

node@{

property=value;

};

};

/*移植者添加的node节点*/

&node{

property=value;

status=“okay”;

}

/*移植者添加demo节点*/

/{

demo{

property=<&node>;

};

};

说明:

demo节点的属性property引用了节点的node的属性值,一般的,引用的目的是使用node节点的部分属性内容

chosen节点

}chosen节点不描述一个真实设备,而是用于firmware传递一些数据给OS,譬如bootloader传递内核启动参数给内核

chosen{

bootargs=“root=/dev/nfsrwnfsroot=192.168.1.1console=ttyS0,115200”;

};

查找节点

}一般的,涉及设备、总线、驱动的概念,即所谓设备信息和驱动代码分离的驱动框架,如platform、i2c、usb、spi、pci、等等;或是分层驱动框架(MTD设备驱动、framebuffer设备驱动、input设备驱动、...),则设备树中设备节点的会内核初始化时候被查找到,驱动代码将不关心节点的查找。

}如果仅仅是接口驱动框架(字符设备驱动、块设备驱动、网络设备驱动),则需要使用内核节点查找函数查找设备树中的设备节点。

查找办法

}通过节点的compatible属性值查找指定节点

}通过节点名查找指定节点

}通过节点路径查找指定节点

节点描述

头文件:

include/of.h

structdevice_node{

constchar*name;//节点名

constchar*type;//设备类型

phandlephandle;

constchar*full_name;//全路径节点名

structfwnode_handlefwnode;

structproperty*properties;

structproperty*deadprops;/*removedproperties*/

structdevice_node*parent;////父节点指针

structdevice_node*child;//子节点指针

structdevice_node*sibling;

structkobjectkobj;

unsignedlong_flags;

void*data;

#ifdefined(CONFIG_SPARC)

constchar*path_component_name;

unsignedintunique_id;

structof_irq_controller*irq_trans;

#endif

};

功能:

通过compatible属性查找指定节点

structdevice_node*of_find_compatible_node(structdevice_node*from,

constchar*type,constchar*compat);

参数:

structdevice_node*from-指向开始路径的节点,如果为NULL,则从根节点开始

constchar*type-device_type设备类型,可以为NULL

constchar*compat-指向节点的compatible属性的值(字符串)的首地址

返回值:

成功:

得到节点的首地址;失败:

NULL

示例:

np=of_find_compatible_node(NULL,NULL,"fsl,imx23-digctl");

digctrl=of_iomap(np,0);

linux-3.12.10-ti2013.12.01\arch\arm\boot\dts\

digctl:

digctl@8001c000{

compatible="fsl,imx28-digctl","fsl,imx23-digctl";

reg=<0x8001c0000x2000>;

interrupts=<89>;

status="disabled";

};

功能:

设备ID表结构,用于匹配设备节点和驱动

structof_device_id{

charname[32];/*设备名*/

chartype[32];/*设备类型*/

charcompatible[128];/*用于与设备树compatible属性值匹配的字符串*/

constvoid*data;/*驱动私有数据*/

};

//注册支持设备树的设备ID表

include/module.h

MODULE_DEVICE_TABLE(of,ID表首地址)

示例:

staticDEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table)={

{PCI_VDEVICE(ADLINK,0x6208),BOARD_PCI6208},

{PCI_VDEVICE(ADLINK,0x6216),BOARD_PCI6216},

{0}

};

MODULE_DEVICE_TABLE(pci,adl_pci6208_pci_table);

功能:

通过compatible属性查找指定节点

structdevice_node*of_find_matching_node(structdevice_node*from,

conststructof_device_id*matches);

参数:

structdevice_node*from-指向开始路径的节点,如果为NULL,则从根节点开始

conststructof_device_id*matches-指向设备ID表,注意ID表必须以NULL结束

示例:

conststructof_device_idmydemo_of_match[]={

{.compatible="fs4412,mydemo",},

{}

};

返回值:

成功:

得到节点的首地址;失败:

NULL

功能:

通过路径查找指定节点

structdevice_node*of_find_node_by_path(constchar*path);

参数:

constchar*path-带全路径的节点名,也可以是节点的别名

返回值:

成功:

得到节点的首地址;失败:

NULL

data->current_node=of_find_node_by_path("/");

功能:

通过节点名查找指定节点

structdevice_node*of_find_node_by_name(structdevice_node*from,

constchar*name);

参数:

structdevice_node*from-开始查找节点,如果为NULL,则从根节点开始

constchar*name-节点名

返回值:

成功:

得到节点的首地址;失败:

NULL

节点属性

有默认意义的属性

}1、设备树语法中已经定义好的,具有通用规范意义的属性。

}一般的,如果是设备信息和驱动分离框架的设备节点,则能够在内核初始化找到节点时候,自动解析生成相应的设备信息。

}常见属性的有:

compatible、地址address、中断interrupt

}ARMLinux内核定义好的,一类设备通用的有默认意义

的属性

}一般的,不能被内核自动解析生成相应的设备信息,但是内核已

经编写了相应的解析提取函数。

}常见属性的有:

MAC地址、GPIO口、clock、power、regulator、等等

驱动自定义属性

}针对具体设备,有部分属性很难通用,需要驱动自己定义好,通过内核的属性提取解析函数进行值的获得。

ethernet@{

compatible=“davicom,dm9000”;

reg=<0x0x20x0x2>;

interrupt=<74>;

local-mac-address=[0000deadbeef];

davicom,no-eeprom;

reset-gpios=<&gpf12GPIO_ACTIVE_LOW>;

vcc-supply=<ð0_power>;

};

compatible属性

一般的,用于匹配设备节点和设备驱动,规则是驱动设备ID表中的compatible域的值(字符串),和设备树中设备节点中的compatible属性值完全一致,则节点的内容是给驱动的。

}设备树中的命名规范如下

/{

node{

compatible=“厂商名,名称”;

...

};

...

};

vcc-supply=<ð0_power>;

};

设备树示例

/{

mydemo{

compatible=“fs4412,mydemo”;

}

}

/*platform框架的探测函数*/

staticintdemo_probe(structplatform_device*devices)

{

//设备树对应节点的信息已经被内核构造成structplatform_devic

}

staticconststructof_device_iddemo_of_matches[]={

{.compatible=“fs4412,mydemo”,},

{}

}

MODULE_DEVICE_TABLE(of,demo_of_matches);

staticstructplatform_driverdemo_drv={

.driver={

.name=DEMONAME,

.owner=THIS_MODULE,

.of_match_table=of_match_ptr(demo_of)

}

}

属性-address

#address-cells:

描述子节点reg属性值的地址表中首地址cell数量

#size-cells:

描述子节点reg属性值的地址表中地址长度cell数量

reg:

描述地址表

/{

parent-node{

#address-cell=<1>;

#size-cells=<1>;

son-node{

reg=;

};

};

};

说明:

父节点#address-cells值为1,#size-cells值为1,则子节点中reg的值就是一个首地址紧接着一个地址上都为一个单元。

CPU地址描述

每个CPU都分配了唯一的一个ID,描述没有大小的CPUids

cpus{

#address-cells=<1>;

#size-cells=<0>;

cpu@0{

compatlibe=“arm,cortex-a9”;

reg=<0>;

};

cpu@1{

compatible=“arm,cortex-a9”;

reg=<1>;

};

};

内存映射设备(MemoryMappedDevices)

描述一个设备的内存地址的时候,一般使用1个cell(32bits)描述地址,紧接着1一个cell

(32bits)描述地址长度

/{

#address-cells=<1>;

#size-cells=<1>;

serial@101f0000{

compatible=“arm,p1011”;

reg=<0x101f00000x1000>;

};

gpio@101f3000{

compatible=“arm,p1061”;

reg=<0x101f30000x1000

0x101f40000x0010>;

};

spi@{

compatible=“arm,p1022”;

reg=<0x0x1000>;

};

};

非内存映射设备(NonMemoryMappedDevices)

}譬如i2c设备,有一个寻址地址,没有内存地址那样的地址长度和范围,一般使用1个cell(32bits)描述该地址,而没有描述地址长度的cell。

i2c@1,0{

compatible=“acme,a1234-i2c-bus”;

#address-cells=<1>;

#size-cells=<0>;

reg=<100x1000>;

rtc@58{

compatible=“maxim,ds1338”;

reg=<58>;

};

};

地址转换范围Ranges(AddressTranslation)

有些设备是有片选的,就需要描述片选及片选的偏移量,在说明地址时,还需要说明地

址映射范围。

/{

compatible=“acme,coyotes-revenge”;

#address-cells=<1>;

#size-cells=<1>;

external-bus{

#address-cells=<2>;

#size-cells=<1>;

ranges=<000x0x10000//片选1,ethernet

100x0x10000//片选2,i2c控制器

200x0x>;//片选3NORFLASH

ehternet@0,0{

compatible=“smc,smc91c1111”;

reg=<000x1000>;

};

};

};

说明:

片选0,偏移0(选中了网卡),被映射到CPU地址空间的0x~0x中,地址长度为0x10000

属性-interrupt

/{

compatible=“acme,coyotes-revenge”;

#address-cells=<1>;

#size-cells=<1>;

interrupt-parent=<&intc>;

interrupt-parent标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的;

serial@101f0000{

compatible=“arm,p1011”;

reg=<0x101f00000x1000>;

interrupt=<10>;

interrupts一个中断标识符列表,表示每一个中断输出信号

};

intc:

interrupt-controller@

compatible=“arm,p1190”;

reg=<0x0x1000>;

interrupt-controller;

#interrupt-cells=<2>;

interrupt-controller一个空属性用来声明这个node接收中断信号;

#interrupt-cells这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符;

};

};

一般的,如果父节点的#interrupt-cells的值是3,则子节点的interrupts一个cell三个32bits整型值:

<中断域中断触发方式>

}实际解析情况,得根据实际使用内核的设备树参加资料来决定。

/{

gic:

interrupt-controller@{

compatible=“arm,cortex-a9-gic”;

#interrupt-cells=<3>;

interrupt-controller;

cpu-offset=<0x4000>;

reg=<0x0x10000>,<0x0x10000>;

};

pinctl@{

gpx0:

gpx0{

gpio-controller;

#gpio-cells=<2>;S

interrupt-controller;

interrupt-parent=<&gic>;

interrupts=<0160>,<0170>,<0180>,<0190>,

<0200>,<0210>,<0220>,<0230>;

#interrupt-cells=<2>;

};

};

ethernet@{

compatible=“davicom,dm9000”;

reg=<0x0x20x0x2>;

interrupt-parent=<&pgx0>;

interrupts=<64>;

davicom,no-e

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2