设备树下的属性和特殊节点

目录

一、 compatible 属性

二、 #address-cells 和#size-cells 属性

三、根节点compatible属性

四、aliases 子节点

五、chosen子节点


在设备树中一般节点命名格式如下:

node-name@unit-address

        其中“node-name”是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的
功能,比如“uart1”就表示这个节点是 UART1 外设。“unit-address”一般表示设备的地址或寄
存器首地址,如果某个节点没有地址或者寄存器的话“unit-address”可以不要,比如“cpu@0”。

一、 compatible 属性

        compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序, compatible 属性的值格式如下所示:

"manufacturer,model"

        其中 manufacturer 表示厂商, model 一般是模块对应的驱动名字。

        比如当属性compatible = "fsl,imx6ul-evk-wm8960"的时候,fsl表示厂商是飞思卡尔,imx6ul-evk-wm8960表示驱动模块名字。设备使用该兼容属性在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件,如果查到相匹配的值,则可以使用这个驱动。

二、 #address-cells 和#size-cells 属性

         这两个属性的值都是无符号 32 位整形, #address-cells 和#size-cells 这两个属性可以用在任
何拥有子节点的设备中,用于描述子节点的地址信息。

        #address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位), #size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。 reg 属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>
aips3: aips-bus@02200000 {
 compatible = "fsl,aips-bus", "simple-bus";
 #address-cells = <1>;
 #size-cells = <1>;
 dcp: dcp@02280000 {
 compatible = "fsl,imx6sl-dcp";
 reg = <0x02280000 0x4000>;
 };
 };

        设置 aips3: aips-bus@02200000 节点#address-cells = <1>, #size-cells = <1>,说明 aips3: aips-bus@02200000 子节点起始地址长度所占用的字长为 1,地址长度所占用的字长也为 1。
        子节点 dcp: dcp@02280000 的 reg 属性值为<0x02280000 0x4000>,因为父节点设置了#address-cells = <1>, #size-cells = <1>, address= 0x02280000, length= 0x4000,相当于设置了起始地址为 0x02280000,地址长度为 0x40000。

三、根节点compatible属性

        在没有使用设备树以前, uboot 会向 Linux 内核传递一个叫做 machine id 的值, machine id
也就是设备 ID,告诉 Linux 内核自己是个什么设备,看看 Linux 内核是否支持。 Linux 内核是
支持很多设备的,针对每一个设备(板子), Linux内核都用MACHINE_START和MACHINE_END
来定义一个 machine_desc 结构体来描述这个设备,比如在文件 arch/arm/mach-imx/machmx35_3ds.c 中有如下定义:

 MACHINE_START(MX35_3DS, "Freescale MX35PDK")
 /* Maintainer: Freescale Semiconductor, Inc */
 .atag_offset = 0x100,
 .map_io = mx35_map_io,
 .init_early = imx35_init_early,
 .init_irq = mx35_init_irq,
 .init_time = mx35pdk_timer_init,
 .init_machine = mx35_3ds_init,
 .reserve = mx35_3ds_reserve,
 .restart = mxc_restart,
 MACHINE_END

        根据 MACHINE_START 和 MACHINE_END 的宏定义,展开后如下所示:

static const struct machine_desc __mach_desc_MX35_3DS \
 __used \
 __attribute__((__section__(".arch.info.init"))) = {
 .nr = MACH_TYPE_MX35_3DS,
 .name = "Freescale MX35PDK",
 /* Maintainer: Freescale Semiconductor, Inc */
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
 };

其中MACH_TYPE_MX35_3DS 就 是 “ Freescale MX35PDK ” 这个板子的 machine id 。内核文件include/generated/mach-types.h中定义了大量的宏

        由于uboot 会给 Linux 内核传递 machine id 这个参数, Linux 内核会检查这个 machine id,其实就是将 machine id 与这些 MACH_TYPE_XXX 宏进行对比,看看有没有相等的,如果相等的话就表示 Linux 内核支持这个设备,如果不支持的话那么这个设备就没法启动 Linux 内核。


        引入设备树以后,不在使用machine id,而是使根节点下面的compatible属性值。对于每一个linux内核支持的设备,也同样会有一个MACHINE_START和MACHINE_END来定义一个 machine_desc 结构体。(相当于machine_desc结构体兼容支持设备树和不支持设备树两个版本的linux)只不过,这个结构体不再说由MACHINE_START和MACHINE_END来定义,而是由DT_MACHINE_START和MACHINE_END来定义。

        DT_MACHINE_START和MACHINE_START差不多,只是有一项的是.nr = ~0,,说明引入设备树以后不会再根据 machineid 来检查 Linux 内核是否支持某个设备了。

 在结构体machine_desc里面,有一个成员变量是.dt_compat = imx6ul_dt_compat,,他的内容是(兼容属性列表):

其中板子根节点下compatible属性“fsl,imx6ull”与 imx6ul_dt_compat 中的“fsl,imx6ull”匹配,因此 I.MX6U-ALPHA 开发板可以正常启动 Linux 内核。


接下来简单看一下 Linux 内核是如何根据设备树根节点的 compatible 属性来匹配出对应的 machine_desc:
1)、Linux 内核调用 start_kernel 函数来启动内核, start_kernel 函数会调用setup_arch 函数
2)、setup_arch 函数会调用setup_machine_fdt 函数来获取匹配的 machine_desc,参数就是就是 uboot 传递给 Linux 内核的 dtb 文件首地址(0x83000000), setup_machine_fdt 函数的返回值就是找到的最匹配的 machine_desc。
3)、setup_machine_fdt 函数调用函数 of_flat_dt_match_machine 来获取匹配的 machine_desc。
参数1: mdesc_best是 默 认 的 machine_desc;
参 数2: arch_get_next_mach 是 个 函 数 ,此函数的工作就是获取 Linux 内核中下一个 machine_desc 结构体,返回其中的dt_compat成员,每调用一次arch_get_next_mach()函数,返回下一个machine_desc的dt_compat成员。

找到匹配的 machine_desc 的过程就是用设备树根节点的compatible 属性值和 Linux 内核中保存的所以 machine_desc 结构的. dt_compat 中的值比较,看看那个相等,如果相等的话就表示找到匹配的 machine_desc。
查找匹配设备的过程:

四、aliases 子节点

aliases {
 can0 = &flexcan1;
 can1 = &flexcan2;
 ethernet0 = &fec1;
 ethernet1 = &fec2;
 gpio0 = &gpio1;
 gpio1 = &gpio2;
......
 spi0 = &ecspi1;
 spi1 = &ecspi2;
 spi2 = &ecspi3;
 spi3 = &ecspi4;
 usbphy0 = &usbphy1;
 usbphy1 = &usbphy2;
};

        aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。不过一般会在节点命名的时候会加上 label,然后通过&label来访问节点,这样也很方便,而且设备树里面大量的使用&label 的形式来访问节点

五、chosen子节点

        chosen 并不是一个真实的设备, chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数。一般.dts 文件中 chosen 节点通常为空或者内容很少。

在这里插入图片描述

但是,当我们进入到/proc/device-tree/chosen 目录里面,会发现多了 bootargs 这个属性


并且通过cat命令可以查找发现,bootargs就是uboot中设置的bootargs环境变量。
现在有两个疑点:
①、我们并没有在设备树中设置 chosen 节点的 bootargs 属性,那么图 43.6.2.1 中 bootargs
这个属性是怎么产生的?
②、为何 bootargs 文件的内容和 uboot 中 bootargs 环境变量的值一样?它们之间有什么关
系?

解答:fdt_support.c 文件中有个 fdt_chosen 函数。

①该函数会调用函数 fdt_find_or_add_subnode 从设备树(.dtb)中找到 chosen 节点,如果没有
找到的话就会自己创建一个 chosen 节点。
②读取 uboot 中 bootargs 环境变量的内容。
③调用函数 fdt_setprop 向 chosen 节点添加 bootargs 属性,并且 bootargs 属性的值就是环境变量 bootargs 的内容。


        do_bootm_linux 函数会通过一系列复杂的调用,最终通过 fdt_chosen 函数在 chosen 节点中加入了 bootargs 属性。而我们通过 bootz 命令启动 Linux 内核的时候会运行 do_bootm_linux 函数,因此会在chosen子节点下添加bootargs属性。


 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值