深入学习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 
#include 
#include 

#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



你可能感兴趣的:(linux)