linux DTS 分析

1、现在实用的内核3.10已经开始实用DTS方法。


2、dts节点的写法

Nodename@Address{
        compatible=xxx;
        xxx;
};
当设备没有地址时,@Address为非必要。

3、bootloader启动时将加载dtb给内核,内核分析dtb即可知道machine,所以bootloader 不再需要传递设备ID号。

例如:

/ {
	compatible = "rockchip,rk3288";//即可知道machine
	rockchip,sram = <&sram>;
	interrupt-parent = <&gic>;\

4、#address-cell 和 #size-cell分别表示地址和地址长度(length),且仅对接下来将要定义的结点生效

i2c0: i2c@ff650000 {
		compatible = "rockchip,rk30-i2c";
		reg = <0xff650000 0x1000>;
		interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
		#address-cells = <1>;
		#size-cells = <0>;
         rk808: rk808@1b {
		   reg = <0x1b>;//address-cell=1,size-cell=0,所以reg只有一位
		   status = "okay";
	};
}

5、reg仅由母结点address-cell和size-cell定义

  #address-cells = <2>  
  #size-cells = <1>;
。。。 
i2c@1,0 {  
            compatible = "acme,a1234-i2c-bus";  
            #address-cells = <1>;//定义rtc结点的reg  
            #size-cells = <0>;  
            reg = <1 0 0x1000>;//该reg结构由母结点定义,addr-cell=2,size-cell=1,所以reg有3成员。1代表片选,0代表片内便宜,0x1000代表长度  
            interrupts = < 6 2 >;  
            rtc@58 {  
                compatible = "maxim,ds1338";  
                reg = <58>;  
                interrupts = < 7 3 >;  
            };  
        }; 
。。。

6、结点的“引用”

rk_screen: rk_screen{ //xxx:xxx这种格式表示这个结点会被应用,结点名为后者
            compatible = "rockchip,screen";
    };

&rk_screen { //“类似c语言的取地址符号”,引用rk_screen结点
     display-timings = <&disp_timings>;
};

disp_timings: display-timings { //生成的结点名为display-timings。disp_timings会被rk_screen实用
 xxxxx

};

7、root结点的子结点描述的是CPU的视图,因此root子结点的address区域就直接位于CPU的memory区域。经过总线桥后的address往往需要经过转换才能对应的CPU的memory映射。external-bus的ranges属性定义了经过external-bus桥后的地址范围如何映射到CPU的memory区域。

#address-cells = <1>;  
#size-cells = <1>;  
。。。    
external-bus {  
        #address-cells = <2>  
        #size-cells = <1>;  
//ranges是地址转换表,前几位代表地址。由父结点和当前结点address-cell决定。本例中,父address-cell=1,当前address-cell=2,所以前两位代表地址。
//第一位代表系统偏移,第二位代表片内偏移
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet  
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller  
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash  
  
        ethernet@0,0 {  
            compatible = "smc,smc91c111";  
            reg = <0 0 0x1000>;  
            interrupts = < 5 2 >;  
        }; 
ranges是地址转换表,其中的每个项目是一个子地址、父地址以及在子地址空间的大小的映射。映射表中的子地址、父地址分别采用子地址空间的#address-cells和父地址空间的#address-cells大小。对于本例而言,子地址空间的#address-cells为2,父地址空间的#address-cells值为1,因此0 0  0x10100000   0x10000的前2个cell为external-bus后片选0上偏移0,第3个cell表示external-bus后片选0上偏移0的地址空间被映射到CPU的0x10100000位置,第4个cell表示映射的大小为0x10000。




根据提供的引用内容,可以了解到在Linux驱动程序中,需要读取Linux内核中附带的dts文件,并操作设备树DTS的相关节点。同时,还提到了在MTK平台上分析Linux的i2c框架。 对于Linux的i2c设备树(DTS)操作,可以按照以下步骤进行: 1. 首先,需要在设备树中定义i2c控制器和i2c设备节点。在设备树中,使用`i2c`关键字来定义i2c控制器,使用`i2c_device`关键字来定义i2c设备。例如: ```dts i2c { compatible = "i2c"; #address-cells = <1>; #size-cells = <0>; i2c@0 { compatible = "i2c-device"; reg = <0>; // 其他属性 }; }; ``` 2. 在驱动程序中,可以使用`of_find_node_by_name()`函数来查找设备树中的节点。该函数接受一个参数,即节点名称,返回一个指向节点的指针。例如: ```c struct device_node *node; node = of_find_node_by_name(NULL, "i2c"); if (node) { // 找到了i2c节点 // 进行其他操作 } ``` 3. 通过节点指针,可以使用`of_property_read_u32()`函数来读取节点的属性值。该函数接受三个参数,分别是节点指针、属性名称和一个指向变量的指针,用于存储属性值。例如: ```c u32 value; if (of_property_read_u32(node, "reg", &value) == 0) { // 读取成功,可以使用value进行其他操作 } ``` 4. 可以使用`of_get_child_by_name()`函数来获取节点的子节点。该函数接受两个参数,分别是父节点指针和子节点名称,返回一个指向子节点的指针。例如: ```c struct device_node *child; child = of_get_child_by_name(node, "i2c@0"); if (child) { // 找到了子节点 // 进行其他操作 } ``` 5. 最后,记得在驱动程序中使用`of_node_put()`函数来释放节点指针。例如: ```c of_node_put(node); ``` 这样,就可以在Linux驱动程序中进行设备树节点的操作了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值