自学linux驱动从入门到放弃(十)设备树

目录

1.什么是设备树?

2.设备树的结构

3.节点结构

4.节点标准属性

4.1 compatible

4.2 status

4.3 #address-cells #size-cells

4.4 reg

4.5 name

4.6 device_type

4.7 phandle

4.8 virtul-reg

4.9 range

4.10 dma-range

5.特殊节点

5.1 /aliases node

5.2 /chosen node

6."of_"相关函数

6.1 查找节点

6.1.1 of_find_node_by_name

6.1.2 of_find_node_by_type

6.1.3 of_find_compatible_node

6.1.4 of_find_node_by_path

6.2 提取属性值

6.2.1 of_find_property

 6.2.2 of_property_read_u32_index

 6.2.3 of_property_read_u*_array

6.2.4 of_property_read_u*


 

        设备树被引入的背景就不说了。直接来看设备树。

1.什么是设备树?

        设备树是用一种树状的结构和节点,来描述系统中的硬件。每个节点都具有描述被表示的设备的特性的属性/值等。那么有几个概念。

DTS设备树的代码源文件,可以理解为各开发板,对DTSI各节点的引用定制。
DTSI同平台更通用的设备树代码,可以作为头文件定义在DTS文件中。
DTCDTS编译文件,可以编译DTS为DTB,也可以将DTB反编译为DTS
DTBDTC编译出来的二进制文件

2.设备树的结构

/dts-v1/;                   
[memory reservations]        
/{
    [property defintions]
    [child node]
};
/dts-v1/;设备树的版本信息
[memory reservations] 预留的内存空间不被内存使用/分配:/memreserve/<address><lenth>;
[property defintions]属性的name和属性的value:property-name = value;

property-name有两种,一种是用户定义的名字如“led-pins”,一种是固定的名字如“compatible”。

value的取值如下:

empty可以为空如:enable-active-high;
<u32>
32位数据:tx_delay = <0x30>;
<u64>
两个32位数据:<0x11223344 0x55667788>.
<string>
字符串:compatible = "silergy,syr827";
<prop-encoded-array>
规定值:status = "okay";
<phandle>
phandle值:基本不推荐使用了
<stringlist>
多个字符串:“hello”,”world”
十六进制数
local-mac-address = [00 00 12 34 56 78];
or:local-mac-address = [000012345678];
节点的引用
interrupt-parent = < &mpic >;
or:interrupt-parent = < &{/soc/interrupt-controller@40000} >;
没有<>的节点引用
ethernet0 = &EMAC0; 这里&EMAC0会被展开为节点的全路径


3.节点结构

        设备树只有一个根节点'/',和若干个节点node1,node2....如果这些节点下还有节点如node1下有节点node-a,那么node-a称之为子节点,node1为它的父节点。

[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
};
[label:]节点的标识,方便引用
node-name节点的名字
[@unit-address]节点内存的起始地址(如果没有相同名字节点需要区分,可省略)

4.节点标准属性

4.1 compatible

        该节点用于匹配platform Driver,当该属性的名字和platform_drvier中的of_match_table匹配时,则驱动匹配上,会执行probe函数。

例: compatible = "active-semi,act8846";

4.2 status

        节点的状态,可用、禁用等,有错误等。

valueDescription
"okay"设备可用
"disabled"设备禁用
"fail"设备出现了错误,不可用
"fail-sss"设备出现了错误,错误内容为"sss"
例: status = "okay";

4.3 #address-cells #size-cells

#address-cells指定子节点中"reg"属性的地址是由几个32位数表示
#size-cells指定子节点中"reg"属性的地址长度是由几个32位数表示
 bus_intmem@ff700000 {
                compatible = "mmio-sram";
                reg = <0x0 0xff700000 0x0 0x18000>;
                #address-cells = <1>;    //用1个32位数表示地址
                #size-cells = <1>;        //用1个32位数表示长度
                ranges = <0 0x0 0xff700000 0x18000>;
                smp-sram@0 {
                        compatible = "rockchip,rk3066-smp-sram";
                        reg = <0x00 0x10>;    //这里就是体现
                };

4.4 reg

        用来定义地址/寄存器的起始地址和长度,里面的值由#address-cells #size-cells来指定。

格式:reg = <addr1 lenth1 addr2 lenth2 ...>

4.5 name

        不建议使用

4.6 device_type

        不建议使用,应该只包含在"cpu"和"memeroy"节点上,但是有些设备也会用该属性去描述,不知道为什么

serial@4600 {
    device_type = "serial";
    compatible = "ns16550";
    reg = <0x4600 0x100>;
    clock-frequency = <0>;
    interrupts = <0xA 0x8>;
    interrupt-parent = <&ipic>;
}

4.7 phandle

        用来指定该节点是设备树中唯一的节点,可以被其他节点来使用,进而关联该节点,现在一般不用了。

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};

another-device-node {
    interrupt-parent = <1>;
};

4.8 virtul-reg

        没研究

4.9 range

        没研究

4.10 dma-range

        没研究

5.特殊节点

5.1 /aliases node

        官方的解释为该节点在根节点下,可以为其他节点定义一个别名。先来看个例子。

/ {
        compatible = "rockchip,rk3288";

        interrupt-parent = <&gic>;

        aliases {
                ethernet0 = &gmac;
                i2c0 = &i2c0;
                i2c1 = &i2c1;
                i2c2 = &i2c2;
                ...
                ...
        };
};

        上面有讲过 property-name = value,当value没有<>时,会被展开为完整路径,上面可以通过反编译看到如"&i2c0"的全路径,下面是个例子。

aliases {
    serial0 = "/simple-bus@fe000000/serial@llc500";
    ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
};

        在网上看了一些文章,内核会解析该节点,通过展开的node path找到该节点,并将别名的id(也就是I2C0,I2C1后面的数字'0','1')解释出来,用来注册驱动和设备。

5.2 /chosen node

        系统启动时所选择的参数,如nfs挂载点等等。

chosen {
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

6."of_"相关函数

6.1 查找节点

6.1.1 of_find_node_by_name

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
功能通过节点名字查找节点
*from开始查找的节点名字,如果'NULL'则从从根节点查找整个设备树
*name要查找的节点名字
返回值查找到的节点指针


6.1.2 of_find_node_by_type

struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
功能通过 'device_type' 的值查找节点
*from开始查找的节点名字,如果'NULL'则从从根节点查找整个设备树
*name要查找的 ‘device_type’属性的value(字符串)
返回值查找到的节点指针

6.1.3 of_find_compatible_node

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)
功能通过 'device_type' 和 'compatible' 两个属性的值查找节点,如果device_type为NULL,则忽略这个属性的从compatible的值查找
*from开始查找的节点,如果为 NULL表示从根节点开始查找整个设备树
*type要查找的节点对应的device_type属性值,'NULL'代表忽略这个属性
 *compatible要查找的节点所对应的 compatible属性值
返回值查找到的节点指针

6.1.4 of_find_node_by_path

struct device_node *of_find_node_by_path(const char *path)
功能通过节点的全路径来查找节点
*path节点的全路径
返回值查找到的节点指针

6.2 提取属性值

6.2.1 of_find_property

property *of_find_property(const struct device_node *np, const char *name, int *lenp)
功能查找属性
*np节点指针
*name属性的名字
*lenp属性的value长度
返回值查找到的节点指针

 6.2.2 of_property_read_u32_index

int of_property_read_u32_index(const struct device_node *np, const char *propname,                   
                               u32 index, u32 *out_value);
功能读取属性的32位无符号的值
*np节点指针
*propname属性的名字
index属性值的index
 *out_value读取到的值
返回值0读取成功,非0读取失败
opp-microvolt = <1111 2222 3333>;    //该属性的value是3个32位无符号的整形值

如果这时候函数的index为0,那么读到的值为'1111'

 6.2.3 of_property_read_u*_array

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);

int of_property_read_u64_array(const struct device_node *np,
            const char *propname,u32 *out_values, size_t sz);
功能属性值是多个u8(u16,u32,u64)数,可以一次性读出来
*np节点指针
*propname属性的名字
*out_values读取到的数组指针
 sz要读取的数组成员的数量
返回值0读取成功,非0读取失败

6.2.4 of_property_read_u*

int of_property_read_u8(const struct device_node *np, const char *propname, 
                        u8 *out_value)
int of_property_read_u16(const struct device_node *np, const char *propname, 
                        u16 *out_value)
int of_property_read_u32(const struct device_node *np, const char *propname, 
                        u32 *out_value)
int of_property_read_u64(const struct device_node *np, const char *propname, 
                        u64 *out_value)
功能属性的值只有一个u8(u16,u32,u64)的值,读取该值
*np节点指针
*propname属性的名字
*out_values读取到的值的指针
返回值0读取成功,非0读取失败
备注:这些函数完全可以用_array的函数替代,只不过sz变量设置为1就行

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值