赞
踩
设备树(Device Tree)是一套用来描述硬件属性的规则。在 2011年3月17日的ARM Linux 邮件列表中进行了推动,因此从linux3.x开始,linux内核引入了设备树。内核中关于设备树的文档位于kernel/Documentation/devicetree/目录。
1)当注册硬件设备发生变化或改动时,需要重新编译内核。
2)内核版本升级时,需要重新移植自定义的已注册设备代码。
这导致了设备树注册设备的方式,最终替代了编写代码注册设备的方式
inux-3.x及之后
在/proc/device-tree/下能够看到设备树的完整形态
在init_boot镜像中,主要包含了init进程的第一阶段实现
vendor_boot镜像中,主要包含了厂商提供的内核驱动文件、fstab文件、内核加载地址、ramdisk加载地址、randisk size、dtb加载地址、dtb size等信息
merge DTB需要使用到工具,在MTK的lk和高通的ABL里面都有源码实现。下面提取了这些实现,编写一个一个dtbmerge工具。
使用 dtc
编译 .dts
时,您必须添加选项 -@
以在生成的 .dtbo
中添加 __symbols__
节点。__symbols__
节点包含所有带标签节点的列表,DTO 库可使用这个列表作为参考
设备树是支持在dts文件中,include .h文件,也支持部分C语言的语法。
#include "son.dtsi"
#include "cfg.h"
#ifdef ENABLE //在cfg.h中定义
adi,internal-ref-microvolt = <0x3e8000>;
#else
adi,internal-ref-microvolt = <2500000>;
#endif
overlay机制,只能支持增加、修改节点,不支持删除node
/delete-node/和/delete-prop/指令仅由dtc编译器在单个编译中使用。
设备树blob格式中没有任何内容来表示删除属性或节点的概念
属性操作的接口函数
操作提取设备树函数
static inline bool device_property_read_bool(struct device *dev, const char *propname)
static inline int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
。。。
static inline int device_property_read_u64(struct device *dev, const char *propname, u64 *val)
int device_property_read_u8_array(struct device *dev, const char *propname, u8 *val, size_t nval)
获取数组长度:static inline int device_property_count_u8(struct device *dev, const char *propname)
字符串:int device_property_read_string(struct device *dev, const char *propname, const char **val)
int device_property_read_string_array(struct device *dev, const char *propname, const char **val, size_t nval)
Linux设备驱动模型,由总线(bus)、设备(device)、驱动(driver)三部分组成;总线是处理器与设备之间的通道,在设备模型中,所有的设备都通过总线相连;总线作为Linux设备驱动模型的核心架构,系统中的设备和驱动都挂接在相应的总线上,来完成各自的工作
总线、设备、驱动示意图
总线注册,是将一种总线类型注册到内核能够管理的总线集合中
在内核启动时,kernel将设备树根目录下的设备树进行解析,将dtb blom转换为device node。将符合条件的device node注册为platform device
全局链表,存储了完整的device node
什么节点会被注册成platform device
除上述设备转换外,根据一级子节点的情况,代码驱动里面会对部分二级节点进行转换,此时不一定是转换成platform device。例如SPI节点下的二级设备会被转换成spi device;I2C节点下的二级节点设备会被转换成i2C device
ads1015并不是被注册成了platform device,而是被注册成I2C device。这也证明了设备树的二级子目录被注册成什么device,一般由父目录的驱动来决定
linux最小化的分区一般包括uboot、dtb、kernel、rootfs四个部分,qemu作为一个虚拟环境,可以单独访问内核和文件系统,不需要使用uboot。
主设备树中arch/arm/boot/dts/ 这个路径下的disi文件好多 可能有各家厂商的 比如高通的
驱动源码:
// node count
printk("\n\n");
dev_warn(dev, "child node count: %d\n", device_get_child_node_count(dev));
驱动配置
make CROSS_COMPILE=arm-none-linux-gnueabihf- ARCH=arm menuconfig
编译内核
make CROSS_COMPILE=arm-none-linux-gnueabihf- ARCH=arm -j8
硬件电路设计选择一款实现特定功能的芯片,一般比较成熟的量产芯片:
linux内核里面已经有了对芯片的支持,使能内核配置支持即可。
芯片厂家会提供驱动文件,有保密要求的需要向供货厂家索取,如果是非保密的一般可以在官网下载。
网络上自行搜索下载芯片驱动。
定制化芯片一般是参考内核中已有的类似驱动,自行完成开发工作
TI的ads1015为例
可以将当前驱动(ti-ads1015.c)配置项目设置成y编译进内核进行测试(或者直接修改defconfig配置文件)
make CROSS_COMPILE=arm-none-linux-gnueabihf- ARCH=arm menuconfig
在设备树中添加设备节点。一般常用的芯片内核中都有使用说明。在设备树中,参考内核说明,在I2C下添加一个device node。修改:arch/arm/boot/dts/vexpress-v2m.dtsi
ads1015并不是被注册成了platform device,而是被注册成I2C device。这也证明了设备树的二级子目录被注册成什么device,一般由父目录的驱动来决定。
[root@farmer /sys/bus/i2c/drivers/ads1015]$ ls
0-0048 bind uevent unbind
/kernel_platform/msm-kernel/drivers/of/fdt.c
populate_properties()函数为节点的各个属性分配空间,赋值;在设备树中,属性的描述是key = value,struct property结构体中name和value分别对应设备树中的key和value
设备树dts文件中子节点都将转化为一个对应的device_node结构,但并不是所有device_node都会转换为platform_device结构
kernel_platform/msm_kernel/init/main.c
start_kernel
setup_arch
rest_init kernel_init kernel_init_freeable do_basic_setup do_initcalls
...
do_initcall_level
...
of_platformm_default_populate
字符串string/字符串数组string-list,compatible = "xxxxxxxx,xxxxxxxx"
32bit unsigned integers,整形用<>表示,reg = <0x...... 0x.......>
binary data,十六进制用[]表示,local-mac-address = [xx xx xx xx]
空,empty_property
650/kernel_platform/msm-kernel/drivers/i2c/busses/i2c-msm-geni.c
用buildroot编译整个系统,用qemu仿真vexpressa9 - 简书
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。