在学习linux内核的过程中,设备树是必学的一个内容,但是初学设备树时,我们经常会对设备树里面的内容一知半解。
笔者在初学的时候,只会裁剪linux系统内核,具体就是在config文件中将配置修改为等于Y、等于N或者等于M,然后在设备树中,只知道某个外设要关闭,那就将status修改"disabled",某个外设要开启,那就那就将status修改"okay"。
但是只是这样是远远不够的,我们还需要了解设备树中外设配置内容的含义。
同时这里做持续更新。
一、简单外设的配置解读-以串口为例
这里以串口驱动为例子。
uart0: serial@30100000 {
compatible = "snps,dw-apb-uart";
reg = <0 0x30100000 0 0x100>;
reg-shift=<2>;
reg-io-width=<4>;
interrupts = <0 17 4>;
clock-frequency=<80000000>;
clock-names = "baudclk";
status = "disabled";
};
以上设备树配置中,该怎么解读呢。
1、uart0: serial@30100000
首先uart0: serial是比较容易理解的,uart0代表物理串口1的意思。serial也是串口的一种表示方法。
但是30100000是什么意思呢?特别是从纯应用软件转学内核的时候,看到30100000是一脸懵逼的,不知道是什么神秘数字。
其实30100000代表是核心板SOC上关于串口操作的寄存器基地址。这个地址具体是多少,还要去查看对应芯片数据手册,linux内核把这些寄存器的操作抽象成接口或者一个文件给到应用层,让应用层专心高效去调用,这样应用层也不用关心串口寄存器要怎么读怎么写怎么配置逻辑的一系列复杂操作。
2、compatible = "snps,dw-apb-uart";
compatible是一个给内核驱动去识别的描述符,我们在写内核驱动在定义对应内核结构体的时候,结构体里面会有of_match_table这个指针,of_match_table中会对应一串字符串。
比如说串口驱动源码里面会在of_match_table里面定义"snps,dw-apb-uart"这么一串字符串,在设备树中对应配置里面,也会定义"snps,dw-apb-uart"这么一串字符串。这样子在串口驱动初始化后,就会根据"snps,dw-apb-uart"这么一串字符串,找到对应的设备树外设外配置,然后再将对应的设备树外设配置加载到内存中做后续操作。
compatible这个描述符还有进阶的用法。
比如说现在我在串口驱动中实现了两种串口使用方法分别为“snps,dw-apb-uart1”和“snps,dw-apb-uart2”,我们实际使用过程中根据项目选择一种就好,没有必要两种都选,那么我就在设备中将compatible配置为“snps,dw-apb-uart1”或者“snps,dw-apb-uart2”就可以。
3、reg = <0 0x30100000 0 0x100>;
这段就是说明当前外设驱动寄存器的访问范围,0x30100000是串口外设的寄存器基地址,0x100表示当前串口外设可以访问0x30100000开始的0x100(十进制是256)个字节地址。
也就是说,当前串口外设寄存器的使用范围为0x30100000到0x3010099。
4、reg-shift=<2>;
这段表示 寄存器偏移量,这里一般不用太在意。
5、reg-io-width=<4>;
这段表示设备访问IO 接口的字节序列,例如16位小端、32位大端等。在dts中配置reg-io-width 属性的值为4或不配置,表示driver-specific,这里一般不用太在意。
6、 interrupts = <0 17 4>;
这段表示的是当前外设中断的分配,这里17表示当前的中断号为17,4表示当前的中断等级。
7、clock-frequency=<80000000>;
这段表示的是当前串口外设的时钟频率。如果时钟频率的话,串口打印的时候可能会有乱码,一般要配置多少频率,在核心板soc芯片数据手册中对应章节,会有推荐值。
8、clock-names = "baudclk";
这段表示的是当前就要用哪一路时钟节点。
9、 status = "disabled";
这段表示是否使能该外设。
二、预留内存reserved-memory
reserved-memory一般情况下不会用到,但是也可以了解一下。
reserved-memory可以隔离出一段内存,不会被应用层用到,一般内核空间会比较多用预留内存,这样内核空间的数据就不会被用户空间影响,具体用法为:
&reserved_memory {
reserved_static: mymem@10000000 {
compatible = "mymem, reserved-memory";
reg = <0x0 0x10000000 0x0 0x10000000>;
no-map;
};
以上这段表示在内存0x10000000开始的地址预留出0x10000000(256MB)大小内存。