Linux设备树的用法(4)

通过在父节点设置合适的#address-cells和#size-cells,地址映射机制可以准确的描述内存映射关系。下面的代码中展示了一个不同片选信息在是如何使用的。

    external-bus {

        #address-cells = <2>

        #size-cells = <1>;

 

        ethernet@0,0 {

            compatible = "smc,smc91c111";

            reg = <0 0 0x1000>;

        };

 

        i2c@1,0 {

            compatible = "acme,a1234-i2c-bus";

            reg = <1 0 0x1000>;

            rtc@58 {

                compatible = "maxim,ds1338";

            };

        };

 

        flash@2,0 {

            compatible = "samsung,k8f1315ebm", "cfi-flash";

            reg = <2 0 0x4000000>;

        };

    };

 

上面的例子中,external-bus使用了两个cell来描述address;一个表示片选号,另一个表示与片选基地址间的偏移量。length区域则用了一个cell来描述。在这个例子中,每个reg节点包含3个cell,分别是:片选号,偏移量,长度

 

非内存映射设备

还有一些设备在总线上并不是不是内存映射型的。他们可以有地址空间,但他们没有通过CPU直接访问地址空间的能力。取而代之的是他们的父设备驱动拥有间接访问内存空间的能力。

 

以I2C设备(不是I2C总线哦)为例子,每个设备被分配了一个地址,没有length这个字段。看起来实际上与cpu的地址分配很相似。

        i2c@1,0 {

            compatible = "acme,a1234-i2c-bus";

            #address-cells = <1>;

            #size-cells = <0>;

            reg = <1 0 0x1000>;

            rtc@58 {

                compatible = "maxim,ds1338";

                reg = <58>;

            };

        };

 

 

Ranges(地址变换)

上文已经讨论过了我们如何分配地址给设备,但是这个所谓的地址仅仅是在设备节点中的本地地址。它无法描述该如何将这些本地的地址映射到CPU能访问的地址空间中。

根节点中一定有描述CPU的地址空间。子节点所用的地址空间就来自与CPU的地址空间,所以不需要进行额外的地址映射。

如:serial@101f0000 就是直接分配的地址0x101f0000。

如果一个节点它不是跟节点下的子节点,那么它就不能用CPU的地址空间。为了能将一个地址空间的地址映射到另一个地址空间,range属性被创造出来了。

下面是在一个简单的设备树中增加range属性。

/ {

    compatible = "acme,coyotes-revenge";

    #address-cells = <1>;

    #size-cells = <1>;

    ...

    external-bus {

        #address-cells = <2>

        #size-cells = <1>;

        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>;

        };

 

        i2c@1,0 {

            compatible = "acme,a1234-i2c-bus";

            #address-cells = <1>;

            #size-cells = <0>;

            reg = <1 0 0x1000>;

            rtc@58 {

                compatible = "maxim,ds1338";

                reg = <58>;

            };

        };

 

        flash@2,0 {

            compatible = "samsung,k8f1315ebm", "cfi-flash";

            reg = <2 0 0x4000000>;

        };

    };

};

 

上面的例子中,ranges属性就定义了一个地址转换规格。在这个表中的每个节点表示一个地址转换关系。

ranges属性中每个字段的大小取决于当前节点的#address-cells,父节点的#address-cells以及当前节点的#size-cells

比如上面的例子中,external-bus节点的地址长度是2,它的父节点的地址长度是1,size长度是1。所以ranges中的三个地址规则可以这样解读:

CS0,偏移量为0的本地地址被映射到父节点地址空间的 0x10100000~0x1010ffff

CS1,偏移量为1的本地地址被映射到父节点地址空间的 0x10160000~0x1016ffff

CS2,偏移量为0的本地地址被映射到父节点地址空间的 0x30000000~0x31000000

更方便的是,如果父节点与子节点的地址空间完全匹配,则子节点可以只定义一个空的ranges属性。

空ranges属性所表示的意思就是子节点的地址空间与父节点地址空间是1:1的映射关系。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/6c0fc219b0ea511bacee7c6ba4b1058e.html