其实这个部分我在前面第四篇笔记中,介绍了这个,这里再展开这个讲讲。
参考资料:《Linux设备驱动开发详解》
1、地址编码
可寻址的设备使用如下信息在设备树中编码地址信息:
reg #address-cells #size-cells
其中,reg的组织形式为
reg=<address1length1[address2length2][address3length3]...>
其中的每一组address length表明了设备使用的一个地址范围。
address为1个或多个32位的整型(即cell),而length的意义则意味着从address到address+length–1的地址范围都属于该节点。若#size-cells=0,则length字段为空。
address和length字段是可变长的,父节点的#address-cells和#size-cells分别决定了子节点reg属性的address和length字段的长度。
在代码清单18.2中,根节点的#address-cells=<1>;和#size-cells=<1>;决定了serial、gpio、spi等节点的address和length字段的长度分别为1。
cpus节点的#address-cells=<1>;和#size-cells=<0>;决定了两个cpu子节点的address为1,而length为空,于是形成了两个cpu的reg=<0>;和reg=<1>;。
external-bus节点的#address-cells=<2>和#size-cells=<1>;
决定了其下的ethernet、i2c、flash的reg字段形如reg=<0 00 x1000>;、reg=<1 00 x1000>;和reg=<2 00 x4000000>;。
其中,address字段长度为2,开始的第一个cell(即“<”后的0、1、2)是对应的片选,第2个cell(即<000x1000>、<100x1000>和<200x1000000>中间的0,0,0)是相对该片选的基地址,第3个cell(即“>”前的0x1000、0x1000、0x1000000)为length。
特别要留意的是i2c节点中定义的#address-cells=<1>;和#size-cells=<0>;,其作用到了I2C总线上连接的RTC,它的address字段为0x58,是RTC设备的I2C地址。(这个意思就是你就在这里,哪里都不需要去)
根节点的直接子书点描述的是CPU的视图,因此根子节点的address区域就直接位于CPU的内存区域。
但是,经过总线桥后的address往往需要经过转换才能对应CPU的内存映射。
2、ranges
external-bus的ranges属性定义了经过external-bus桥后的地址范围如何映射到CPU的内存区域**。**
(设备的内存管理)
ranges是地址转换表,其中的每个项目是一个子地址、父地址以及在子地址空间的大小的映射。
映射表中的子地址、父地址分别采用子地址空间的#address-cells和父地址空间的#address-cells大小。对于本例而言,子地址空间的#address-cells为2,父地址空间的#address-cells值为1,因此0 0 0x10100000 0x10000的
前2个cell为external-bus桥后external-bus上片选0偏移0,(子地址)
第3个cell表示external-bus上片选0偏移0的地址空间被映射到CPU的本地总线的0x10100000位置, (父地址)
第4个cell表示映射的大小为0x10000。 ranges后面两个项目的含义可以类推。(长度length)
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet 1 0 0x10160000 0x10000 // Chipselect 2, i2c controller 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
慢慢看多了就理解了,我这么菜,感觉有时候也很晕乎乎。