关于驱动想说的话:以前总以为高而攀不到。花时间去积累了,总会进步的。
这个世界需要的是全力以赴,战胜他人先战胜子自己!!
Linux Device Tree可描述的信息包括:
- cpu的数量和类型
- 内存基地址和大小
- 总线
- 外设
- 中断控制器
- GPIO控制器
- Clock控制器
bootloader会将这颗树传递给内核,内核根据它展开出linux内核中的platform_device,input_device,spi_device等设备,设备用到内存、GPIO、IRQ 等资源,也被传递到内核,内核将这些资源绑定给相应的设备。
学习的5个步骤,
- dts/dtsi
- device tree compiler工具,该工具将文本格式编译为二进制格式。
- bootloader 如何将指定的二进制格式写入指定的内存位置。
- 内核如何展开二进制文件,获取硬件设备信息。
- 驱动和设备如何注册。
描述文件存放路径: 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