嵌入式


设备树语法

<ol> <li> <p>{}称为节点,/{}称为根节点 标准结构:xxx@yyy{…},xxx是节点的名字,yyy则不是必须的,其值为节点的地址(寄存器地址或其他地址),比如i2c1: i2c@021a0000中的就是一个i2c控制器的寄存器基地址,rtc: pcf8523@68中的就是这个rtc设备的i2c地址</p> </li> <li> <p>属性:地址 正式的设置是在reg属性中设置的比如:<code>reg = &lt;0x021a0000 0x4000&gt;</code>; reg的格式通常为<code>&lt;address length&gt;</code>,0x021a0000是寄存器基地址,0x4000是长度。address 和length的个数是可变的,由父节点的属性<code>#address-cells</code> 和<code>#size-cells</code> 决定,比如节点i2c@021a0000的父节点是aips-bus@02000000,其#address-cells 和#size-cells均为1,所以下面的i2c节点的reg属性就有一个address 和length,而i2c节点本身#address-cells 和#size-cells 分别为1和0,所以其下的rtc: pcf8523@68 的reg属性就只有一个0x68(i2c地址)了</p> </li> <li> <p>属性:兼容性 如果一个节点是设备节点,那么它一定要有compatible(兼容性),因为这将作为驱动和设备(设备节点)的匹配依据,compatible(兼容性)的值可以有不止一个字符串以满足不同的需求,详见下一节。而根节点的compatible也是非常重要的,也就是&quot;fsl,imx6dl&quot;这个字符串,因为系统启动后,将根据根节点的compatible来判断cpu信息,并由此进行初始化</p> </li> <li> <p>属性设置的套路</p> <ul> <li>一般来说,每一种设备的节点属性设置都会有一些套路,比如可以设置哪些属性?属性值怎么设置?那怎么知道这些套路呢,有两种思路 </li> <li>第一种是抄类似的dts,比如我们自己项目的平台是4412,那么就可以抄exynos4412-tiny4412.dts、exynos4412-smdk4412.dts这类相近的dts</li> <li>第二种是查询内核中的文档,比如Documentation/devicetree/bindings/i2c/i2c-imx.txt就描述了imx平台的i2c属性设置方法;Documentation/devicetree/bindings/fb就描述了lcd、lvds这类属性设置方法</li> </ul> </li> <li>节点之间的联系 <ul> <li>节点与节点之间的关联,通常通过“标号引用”和“包含”来实现  所谓<strong>标号引用,就是在节点名称前加上标号</strong>,这样设备树的其他位置就能够通过<strong><code>&amp;</code></strong>符号来调用/访问该节点,比如上面代码ir_recv节点中的gpio属性,就引用了gpio1标号处的节点 包含则是最基本的方式,比如我们要在i2c1接口添加一个i2c外设,那么就必须要在i2c1下面添加一个节点,比如上面代码中的rtc: pcf8523@68 {}</li> </ul></li> </ol> <ul> <li><strong>标号引用常常还作为节点的重写方式</strong>,比如下面代码是imx6qdl.dtsi中定义的i2c节点,而前面imx6dl-hummingboard.dts中的&amp;i2c1,就是对i2c1标号处节点的一次重写,在其内部添加了一个rtc设备</li> <li>如果一个节点是<strong>属性节点</strong>(即仅仅是作为属性被其他节点调用),那么它定义在哪里其实无所谓,重要的是调用的位置,比如lcd屏幕的时序,其实我们完全可以把它定义在其他犄角旮旯,然后在lcd节点下用&amp;来调用它,这也是可以的。这有点类似于函数:在哪定义不重要,重要的是在哪调用</li> </ul> <ol> <li>驱动与节点的匹配 首先,内核必须要知道<strong>dtb文件的地址,这由U-boot来告诉内核</strong>,详见U-boot引导内核流程分析。只要内核知晓了dtb文件的地址,那么驱动就可以通过<strong>一些API任意获取设备树的内部信息</strong></li> </ol> <p>对于3.x版本之后的内核,platform、i2c、spi等设备不再需要在mach-xxx中注册,<strong>驱动程序将直接和设备树里的设备节点进行配对</strong>,是通过设备节点中的<strong><font color=red>compatible(兼容性)</font></strong>来与设备节点进行配对的,这里只做简单介绍,具体的应用详见 基于i2c子系统的驱动分析、 基于platform总线的驱动分析</p> <p><strong>这里以pcf8523驱动为例,只要驱动中的<font color=red>of_match_table</font> 中的compatible 值和设备节点中的compatible 相匹配</strong>,那么probe函数就会被触发。不仅i2c是这样,platform、spi等都是这个原理 <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/26245173c65ef27bc455357d2493079d?showdoc=.jpg" alt="" /></p> <ul> <li>i2c和spi驱动还支持一种“别名匹配”的机制,就以pcf8523为例,假设某程序员在设备树中的pcf8523设备节点中写了compatible = &quot;pcf8523&quot;;,显然相对于驱动id_table中的&quot;nxp,pcf8523&quot;,他遗漏了nxp字段,但是驱动却仍然可以匹配上,因为别名匹配对compatible中字符串里第二个字段敏感</li> </ul> <ol> <li>特殊节点 Linux中的设备树还包括几个特殊的节点,比如chosen,chosen节点不描述一个真实设备,而是用于firmware传递一些数据给OS,比如bootloader传递内核启动参数给内核 <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/26b4c9501244e3f27d547a9f482941b0?showdoc=.jpg" alt="" /></li> </ol> <p>下面的例子中就是直接引用了dtsi中的一个节点,并向其中添加/修改新的属性信息 <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/a9db4fea077f4bb3a1afb62a9b0059cb?showdoc=.jpg" alt="" /></p>

页面列表

ITEM_HTML