Android 驱动开发(14)---深入学习Linux Device Tree

深入学习Linux Device Tree

这个世界需要的是全力以赴,战胜他人先战胜子自己!!

Linux Device Tree可描述的信息包括:

  1. cpu的数量和类型
  2. 内存基地址和大小
  3. 总线
  4. 外设
  5. 中断控制器
  6. GPIO控制器
  7. Clock控制器

bootloader会将这颗树传递给内核,内核根据它展开出linux内核中的platform_device,input_device,spi_device等设备,设备用到内存、GPIO、IRQ   等资源,也被传递到内核,内核将这些资源绑定给相应的设备。

学习的5个步骤,

  1. dts/dtsi
  2. device tree compiler工具,该工具将文本格式编译为二进制格式。
  3. bootloader 如何将指定的二进制格式写入指定的内存位置。
  4. 内核如何展开二进制文件,获取硬件设备信息。
  5. 驱动和设备如何注册。

描述文件存放路径: kernel/arch/arm/boot/dts

Device tree结构约定

Device tree 常用节点类型

所有device tree节点必须有1个根节点/, 还必须在根节点下有如下2个节点:

1、Cpu节点

2、memory节点  ---ePAPR规范指定了memory是必须的节点,名称也必须是memory。内存节点描述了系统物理内存的信息,如果系统中有多个内存范围,device tree中可能会创建多个内存节点,或者在一个单独的内存节点中通过reg属性指定内存的范围、

3、Chosen节点不代表一个真正的节点,只是传到参数的作用,chosen里的数据也不代表硬件。

4、Cpus节点

    必须的节点,不代表真实设备,存放cpu节点的一个容器

5、cpu节点描述具体的硬件执行单元

6、soc节点表示一个系统级的芯片

文档  documentation/devicetree/bindings

DTC (compiler) 

源码位于scripts/dtc

    scripts/dtc/Makefile--hostprogs-y:=dtc  //使能编译

Device Tree Blob (.dtb)

.dtb是.dts被DTC编译后的二进制格式的Device Tree描述,可由Linux内核解析。通常在为电路板制作NAND、SD启动image时,会为.dtb文件单独留下一个很小的区域以存放之,之后bootloader在引导kernel的过程中,会先读取该.dtb到内存。

初始化platform_device

如msm为例:

\arch\arm\mach-msm\board-8940.c

static const char *msm8940_dt_match[] __initconst = {

    "qcom,msm8940",

    NULL

};

static void __init msm8940_init(void)

{

    board_dt_populate(NULL);

}

DT_MACHINE_START(MSM8940_DT,

    "Qualcomm Technologies, Inc. MSM 8940 (Flattened Device Tree)")

    .init_machine = msm8940_init,

    .dt_compat = msm8940_dt_match,

MACHINE_END

\arch\arm\mach-msm\board-8940.c:

#include <linux/kernel.h>

#include <linux/of.h>

#include <linux/of_fdt.h>

#include "board-dt.h"

void __init board_dt_populate(struct of_dev_auxdata *adata)

{

    of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);

    /* Explicitly parent the /soc devices to the root node to preserve

     * the kernel ABI (sysfs structure, etc) until userspace is updated

     */

    of_platform_populate(of_find_node_by_path("/soc"),

                 of_default_bus_match_table, adata, NULL);

}

of_platform_populate 函数从device tree data中获取数据填充platform_device.

对驱动的影响  http://www.wowotech.net/linux_kenrel/dt-code-analysis.html

驱动中需要增加一个OF匹配表。驱动需要与.dts中描述的设备节点进行匹配,引发probe函数执行。

不采用DTS的驱动:

    需要驱动注册平台设备和驱动,当match后执行probe。

使用DTS的驱动:

    平台驱动注册过程中,会检查of_match_table中的设备是否和dts中解析出来的设备匹配,如果匹配则触发probe函数。

对BSP影响

     以前ARM Linux针对不同的电路板会建立由MACHINE_START和MACHINE_END包围起来的针对这个machine的一系列callback,  如:kernel\arch\arm\mach-msm\board-msm8x60.c

MACHINE_START与MACHINE_END http://blog.csdn.net/cxw3506/article/details/8475965

    使用DTS后,MACHINE_START变为DT_MACHINE_START, 其中含有.dt_compat成员,用于表明相关的machine与.dts中的root节点的compatible属性兼容关系。 如果Bootloader传递给内核的Device Tree中的root结点的compatible属性出现在某machine的.dt_compat表中,相关的machine就与对应的Device Tree匹配,从而引发这一machine的一系列初始化函数执行。

如:  kernel\arch\arm\mach-msm\board-8974.c

static const char *msm8974_dt_match[]  __initconst = {

    "qcom,msm8974",

    "qcom,apq8074",

    NULL

};

DT_MACHINE_START(MSM8974_DT, "Qualcomm MSM 8974 (Flattened Device Tree)")

    .map_io = msm8974_map_io,

    .init_irq = msm_dt_init_irq,

    .init_machine = msm8974_init,

    .handle_irq = gic_handle_irq,

    .timer = &msm_dt_timer,

    .dt_compat = msm8974_dt_match,

    .reserve = msm_8974_reserve,

    .init_very_early = msm8974_init_very_early,

    .restart = msm_restart,

    .smp = &msm8974_smp_ops,

MACHINE_END

arch\arm\boot\dts\msm8974-v1-sim.dts

/dts-v1/;

/include/ "msm8974-v1.dtsi"

/include/ "msm8974-sim.dtsi"

/ {

    model = "Qualcomm MSM 8974 Simulator";

    compatible = "qcom,msm8974-sim", "qcom,msm8974", "qcom,sim";

    qcom,msm-id = <126 16 0>,

              <185 16 0>,

              <186 16 0>;

};

Device tree 常用api

api 通常以of_为前缀,用于获取Device tree中的关键信息。实现位于:drivers/of目录。

DTS 例子如 : 

drivers\pinctrl\qcom\pinctrl-msm8937.c  ==>> 

\chips\msm8940\devices\msm8940_64\msm8937-pinctrl.dtsi

猜你喜欢

转载自blog.csdn.net/zhangbijun1230/article/details/81154413