一.设备树的引进

1.1字符设备驱动的三种写法

1.1.1怎么写设备驱动?

  • 看原理图 1. 确定引脚: 2. 看芯片手册:确定如何操作引脚 -写驱动程序(起封装作用,不用涉及硬件)

rk3568 android 设备树_设备驱动

  1. 分配一个结构体:file_operation
  2. 设置结构体成员:
    open = led_open:把led引脚设置为输出引脚
    write = led_write :根据App传入的值,设置引脚状态
  3. 注册(告诉内核,加入驱动链表):利用注册函数 regist_chrdev(主设备号,结构体,name)
  4. 入口:
  5. 出口

1.1.2 驱动中指定引脚的三种方法

  1. 传统方法:在驱动代码中写死
  2. 总线设备驱动模型
    led_drv:注册驱动,入口,出口等等
    led_dev:指定引脚
  3. 使用设备树指明引脚
    led_drv:注册驱动,入口,出口等等
    dts:设备树指定引脚
  • 驱动写法,核心不变,差别在于如何指定硬件资源

1.1.3三种方法指定引脚优缺点

1.1.3.1传统方法:
优点:简单
			缺点:不易拓展,需要重新编译
1.2.3.2总线设备驱动模型:
  1. led_dev.c:负责配置platform_device结构体,指定引脚资源,不同的设备指定不同的资源,我们只需要修改对应的资源,每一个设备就是一个dev.c文件

rk3568 android 设备树_设备树_02

platform_device包含:
			
							.resource:指明引脚资源
							.name:设备名字
  1. led_drv.c:负责配置platform_driver结构体

rk3568 android 设备树_引脚_03

platform_driver包含:	
			
			.id_table:	第一个用来匹配dev和drv的成员属性
			.driver:name等等,找到对应的dev.c	
			.probe:如果匹配成功,分配/设置/注册file_operation结构体,根据APP传入的值,确定对应的引脚,来自平台设备
			.remove:移除设备
  1. 如何匹配dev和drv?
  2. rk3568 android 设备树_设备驱动_04

  3. bus_type 结构体中的platform_match用来比对dev和drv,优先比较drv中id_table和dev中的名字,如果找不到,再比较drv中driver和dev中的名字。
  4. 稍微复杂,易拓展。但是与很多冗余代码,每次更改都需要重新更改
1.1.3.3 设备树:是对平台设备驱动的一种改进
  • 相对于总线设备驱动,drv不变,dev变成dts文件,即指定资源的方式变了。
  • dts中构造节点,节点含有资源,将dts编译成dtb二进制文件,传递给内核,内核会解析dtb文件,得到设备节点device_node,进一步得到platform_device(资源)
  • 对于dts生成的platform_device,含有of_node,of_node里面含有属性,比如compatible,pin等
    1. led_drv.c:负责分配/设置/注册:platform_device(同总线方法一样)
    2. dts:指定资源,更换单板时,只需修改dts文件,最后会生成dtb文件
    3. 无冗余代码,不要重新编译内核或驱动,只需提供不一样的设备树文件

1.2 dts

1.2.1 dts格式

DTS文件布局(layout);
/dts-v1/; 表示dts的版本
[memory  reservations]           //格式为   /memreserve/ <adress><length>;表示保留的内存区域
/{  根,设备树的起点
		[property definitions]属性
		[child nodes]子节点,同一级别的节点名字互不相同

};
                                            Property 格式1:
                                            [lable:]   property-name = value;
                                            value的表达方式:
                                            			1.<1  0x1  0x123>:表示3个32位数据array of cell
                                            			2."字符串"
                                            			3.[00 11 22]:byte string,16进制表示的一个或多个byte,必须用俩位
                                            			             16进制数表示,空格可以省略
                                            			4.可组合多种类型的值,中间用逗号分开              
                                            			

 											Property 格式2:(没有值)
 											[lable:]property-name;

											Devicetree node 格式:
											[lable:] node-name[@unit-address]{
												[properties definatons]
												[]child nodes
											};

1.2.2 dts特殊的,默认属性

  • /根节点
    1. #address-cells //在他的子节点reg属性中,使用多少个u32整数来描述地址
    2. #size-cells //在他的子节点reg属性中,使用多少个u32整数来描述大小
    3. compatible // 定义一系列的字符串,用来指定内核中哪个machhine_desc可以支持本设备,即这个板子兼容哪些平台,uImage
    4. model //这个板子是什么,比如两个板子的配置基本一致,他们的compatible是一样的,那么就通过,model来分辨
  • /memory
    device_type = “memory”;
    reg //用来指定内存的地址和大小
  • /chosen
    bootarges //内核command line参数,跟u-boot中设置的bootarges的作用是一样的
  • /cpus
    device_type = “cpu”
    reg //表明自己是哪个cpu

1.2.3引用其他节点

  • phandle://节点中的phandle属性,他的取值必须是唯一的(不要跟其他节点的phandle值是一样的)

例:

pic@10000000{
	phandle = <1>;
	interrupt-controller;//中断控制器

};
another-device-node{
	interrupt-parent = <1>;//引用phandle值为1的节点

}
  • lable:
PIC:pic@10000000{
	interrupt-controller;//中断控制器

};
another-device-node{
	interrupt-parent = <&PIC>;//使用lable来引用上述节点,使用lable实际上也是使用phandle来引用,
							//在编译dits文件为dtb时,编译器dtc会在dtb中插入phandle属性

}

1.3 dtb

1.3.1 dtb格式

rk3568 android 设备树_rk3568 android 设备树_05

  1. struct _ftd_header:头部·用来表明各个分部的偏移地址
  2. memory reservation block:保留的内存空间信息
  3. structure block:主体结构
  4. string block:属性的名字,以00结尾

1.3.2 struct _ftd_header

rk3568 android 设备树_嵌入式_06

1.3.3 memory reservation block

rk3568 android 设备树_嵌入式_07

1.3.4 structure block

  1. FDT_BEGIN_NODE(0X0000 0001):节点的开头,+节点名字(根节点除外)
  2. FDT_END_NODE(0X0000 0002):节点的尾部
  3. FDT_PROP(0X0000 0003):表示一个属性的开始,+ 一个结构体 ,+ value

rk3568 android 设备树_设备驱动_08

len表示value的长度,nameoff表示属性的名字在string block的偏移量

4.FDT_END(0X0000 0009):整个structure结束