Device Tree的用法
发布日期:2021-06-29 02:32:49 浏览次数:2 分类:技术文章

本文共 15152 字,大约阅读时间需要 50 分钟。

Device Tree的用法----http://www.right.com.cn/forum/thread-146260-1-1.html
基本数据格式
Device tree是一种简单的节点和属性的树形结构。属性是键值对,而节点可能包括属性和子节点。例如,下面是.dts格式的树形结构:
/ {
    node1 {
        a-string-property = "A string";
        a-string-list-property = "first string", "second string";
        a-byte-data-property = [0x01 0x23 0x34 0x56];
        child-node1 {
            first-child-property;
            second-child-property = <1>;
            a-string-property = "Hello, world";
        };
        child-node2 {
        };
    };
    node2 {
        an-empty-property;
        a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
        child-node1 {
        };
    };
};
此树形结构很明显的是毫无用处,因为它没描述任何东西,但它确实展示了节点属性的结构。主要有:
1   一个单独的root node:“/
2   一对子节点:“node1”和“node2
3   节点1的一对子节点:“child-node1”和”child-node2
4   分散于树形结构当中的一些属性
属性是简单的键值对,此处的值可以为空,也可以包括任意的字节流。当数据类型没有被编进数据结构时,会有一些基础数据表示法能够在device tree源文件中进行表达。
5  文本串可以用双引号表示
a  string-property = "a string"
6   单元格是由尖括号分隔的32 bit无符号整数
a  cell-property = <0xbeef 123 0xabcd1234>
7   二进制数据使用的是方
a  binary-property = [0x01 0x23 0x45 0x67];
8   不同示意的数据可以用逗号串联在一起
a mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
9   逗号也用来创建字符串列表
a  string-list = "red fish", "blue fish";
基本概念
要了解如何使用device tree,我们先从样机和创建一个device tree开始。
样机
以下为虚拟机,由”Acme”制造,名为“Coyote’s Revenge”。
1   一个32bit ARM CPU
2   附属于内存映射串行端口的处理器本地总线,spi总线控制器,i2c控制器,中断控制器和外总线桥
3   256MBSDRAM
4   基于0X101F10000X101F20002串行端口
5   基于0x101F3000GPIO控制器
6   基于0X1017000的拥有以下设备的SPI控制器
a  附属于GPIO #1的有SS pinMMC slot
7   拥有以下设备的外部总线桥
a  附属于基于0x101100000外总线的SMC91111以太网设备
b  拥有以下设备的基于0x10160000i2c控制器
c  Maxim DS1338 real time clock。响应slave address 1101000(0x58)
8  基于0x3000000064MBNOR flash
初始结构
第一步是为设备创建一个骨架结构。这是一具有效的device tree所需的最基本的结构。现在你想唯一的标识此设备。
/ {
    compatible = "acme,coyotes-revenge";};
C
ompatible指定了系统的名称。它包括字符串<manufacturer>,<model>。指定确切的设备是很重要的一点,并且包含制造商以避免命名空间冲突。操作系统将使用compatible值来决定如何在设备上运行,那么将正确数据加入属性中就显得非常重要。
理论上,compatibleOS所需的唯一指定设备的所有数据。如果所有设备资料都是硬编码,那么OS可以在高级compatible属性查找“acme,coyotes-revenge”。
28729612872 79612872
 
   
 
高级中断映射
现在我们开始最有趣的部分,PCI中断映射。一个PCI设备能够使用#NTA,#NTB,#NTC和#NTD来触发中断。如果我们没有多功能PCI设备,就会有某个设备负责使用#NTA来进行中断。然而每个PCI插口或设备都会被连线到中断控制器的不同输入。所以device tree需要一种方式将每个PCI中断信号映射到中断控制器的输入。#interrupt-cells,interrupt-map和interrupt-map-mask属性用来描述中断映射。
事实上,这里描述的中断映射并不局限于PCI总线,任何节点都可以指定复杂的中断映射,但PCI是最常见的情况。
pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-ranges = <0 0>;
            #address-cells = <3>
            #size-cells = <2>;
            ranges = <0x42000000 0 0x80000000  0x80000000  0 0x20000000
                      0x02000000 0 0xa0000000  0xa0000000  0 0x10000000
                      0x01000000 0 0x00000000  0xb0000000  0 0x01000000>;
            #interrupt-cells = <1>;
            interrupt-map-mask = <0xf800 0 0 7>;
            interrupt-map = <0xc000 0 0 1 &intc  9 3 // 1st slot
                             0xc000 0 0 2 &intc 10 3
                             0xc000 0 0 3 &intc 11 3
                             0xc000 0 0 4 &intc 12 3
                             0xc800 0 0 1 &intc 10 3 // 2nd slot
                             0xc800 0 0 2 &intc 11 3
                             0xc800 0 0 3 &intc 12 3
                             0xc800 0 0 4 &intc  9 3>;
        };
首先你将注意到PCI中断编号只使用一个cell,与使用两个cell的系统中断控制器不同,一个是irq编号,另一个是为了标记。
在示例中,我们有两个4中断线的PCI插槽,所以我们需要将8个中断线映射到中断控制器。这是通过使用interrupt-map属性实现的。
因为中断编号不足以区分位于单独PCI总线的一些PCI设备,我们也需要指出是哪个PCI设备触发中断线。幸运的是我们可以使用每个PCI设备都有一个唯一设备编号。想要区分一些PCI设备的中断,我们需要一个元组,包括PCI设备编号和PCI中断编号。简单来了说,我们要构建一个拥有4 cell的单元中断说明符:
        三个#address-cells,包括phys.hi,phys.mid,phys.low,和
        一个#interrupt-cell(#INTA,#INTB,#INTC,#INTD)
因为我们只需要PCI地址的设备编号部分,此时可以使用interrupt-map-mask属性。Interrupt-map-mask也是4-元组,像单元中断说明符一样。在示例中可以看到我们只需要phys.hi设备编号部分,并且我们需要3 bit来区分四个中断线。
现在我们可以创建interrupt-map属性。此属性是一个表格,每个在此表格的输入包括子单元中断说明符,一个母handle和一个母单元中断说明符。所以在第一个可以读出PCI中断#INTA被映射到IRQ9。
单元中断说明符最重要的部分是源于phys.hi bit字段的设备编码。设备编码取决于每个PCI主机控制器是如何启用每个设备上的IDSEL pin的。在此示例中,PCI插槽被分配了设备id 24 (0x18),并且PCI插槽2被分配到了设备id 25 (0x19)。每个插槽的phys.hi值是由设备编码移位来了决定的,如下:
        为插槽1的phys.hi是0XC000
        为插槽2的phys.hi是0Xc800
将这些放在一起,interrupt-map属性显示:
        为插槽1的#INTA是IRQ9,主中断控制器的低敏感
        为插槽1的#INTB是IRQ10,主中断控制器的低敏感
        为插槽1的#INTC是IRQ11,主中断控制器的低敏感
        为插槽1的#INTD是IRQ12,主中断控制器的低敏感
并且
        为插槽2的#INTA是IRQ10,主中断控制器的低敏感
        为插槽2的#INTB是IRQ11,主中断控制器的低敏感
        为插槽2的#INTC是IRQ12,主中断控制器的低敏感
        为插槽2的#INTD是IRQ9,主中断控制器的低敏感
最后需要注意的是,与interrupt-parent属性相似,一个节点的interrupt-map属性会为所有子节点改变默认中断控制器。在此PCI示例中,这意味着PCI主机桥会成为默认中断控制器。如果通过PCI总线附加上一个设备,而此设备与另外一个中断控制器直接相连的话,它仍然需要指定自己的interrupt-parent属性。
欢迎大家提出自己的想法和意见,可以以回复的形式提出,或者加入我的QQ群大家一起交流,互相学习。
      名   称:openwrt开发
      群   号:  79612872
 
 

举报

   
 楼主
|
发表于 2014-8-11 10:27
|
本帖最后由 radixdigit 于 2014-8-11 10:53 编辑
CPU
下一步是描述CPU。一个名为“cpus”的container node为每个CPU添加了一个子节点。在此情况下此系统为源于ARM的双核Cortex A9系统。
/ {
    compatible = "acme,coyotes-revenge";
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };
};
在每个cpu节点的兼容属性是字符串<manufacturer>,<model>,用以指定确切的cpu,就像是高级兼容属性一样。
此后会向cpu节点添加更多的属性,但我们首先要谈的是一些基本概念。
节点名称
我们值得花一些时间来谈论命名规范。每个节点都必须有一个名称,形式是<name>[@<unit-address>]。
<name>是一个简单的ascii字符串,长度可以达到31个字符。通常节点名称是依据它所代表的设备。例如一个3com以太网适配器应该使用的名称为ethernet,而不是3com509。
如果节点是用一个adress来描述设备的,那么就应该包括Unit-address。通常unit address是用来接入设备的原地址,并列入到节点的reg属性。我们将在下文提及reg属性。
同级节点必须有唯一名称,但是只要地址不同,不只一个节点会使用相同的属名(例如,serial@101f1000 & serial@101f2000)。
设备
系统中的每个设备都由一个device tree节点所代表。下一步是要为每个设备用节点填充树形结构。现在新节点将会为空,直到我们了解如何处理地址范围和终端请求。
/ {
    compatible = "acme,coyotes-revenge";
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };
    serial@101F0000 {
        compatible = "arm,pl011";
    };
    serial@101F2000 {
        compatible = "arm,pl011";
    };
    gpio@101F3000 {
        compatible = "arm,pl061";
    };
    interrupt-controller@10140000 {
        compatible = "arm,pl190";
    };
    spi@10115000 {
        compatible = "arm,pl022";
    };
    external-bus {
        ethernet@0,0 {
            compatible = "smc,smc91c111";
        };
        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            rtc@58 {
                compatible = "maxim,ds1338";
            };
        };
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
        };
    };
};
此树形结构中,在系统里为每个设备添加了一个节点,并且层级结构也反映出设备是如何与系统相关联的。例如外总线的设备是外总线节点的子节点,i2C设备是i2c总线控制器节点的子节点。通常系统的层级结构代表了CPU的视图。
此时这个树形结构是无效的。它缺失设备间相关联的信息。过后会将这些数据添加上去。需要注意的是:
        每个设备节点都有一个compatible属性
        Flash节点在兼容属性中有两个字符串。
        如前文所提,节点名称代表了设备类型,并不是详细型号。
了解compatible属性
树形结构中代表一个设备的每个节点都要求拥有compatible属性。Compatible是操作系统决定使用哪个设备驱动程序的关键。
Compatible是字符串列表。列表中第一个字符串“<manufacturer>,<model>”指定了节点代表的确切的设备。以下字符串代表了其它设备。
例如,位于芯片上的Freescale MPC8349系统拥有一个串行设备,此设备是National Semiconductor ns16550注册界面的工具。MPC8349串口设备的compatible属性应该为:compatible = "fsl,mpc8349-uart", "ns16550"。此时fsl,mpc8349-uart指定了确切的设备,ns16550表示与National Semiconductor 16550 UART兼容。
注:ns16550由于历史原因没有制造商前缀。所有新的compatible值都应该使用制造商前缀。
此练习允许已存在设备驱动程序绑定到设备上,但仍然是唯一指定确切的硬件。
注:不要使用wildcard compatible值,如:fsl,mpc83xx-uart或类似的。如果它没有及时进行变更,Silicon供应商的变更会打破你的wildcard假设。你可以选择一个特定的silicon执行程序并将所有后期的silicon与之相兼容。
欢迎大家提出自己的想法和意见,可以以回复的形式提出,或者加入我的QQ群大家一起交流,互相学习。
      名   称:openwrt开发
      群   号:  79612872
 
 

举报

   
 楼主
|
发表于 2014-8-14 09:42
|
寻址的运行
可寻址的设备是使用以下属性将地址信息编入device tree的:
n   Reg
n   #address-cells
n   #size-cells
每个可寻址设备都会得到一个reg,它是一个元组列表:reg = <address1 length1 [address2 length2] [address3 length3] ... >。每个元组代表设备的地址范围。每个address值是一个或多个被叫做cells的32bit整数的列表。类似的,长度值可以为cells列表或为空。
由于地址或长度字段都是可变的,母节点的#address-cells和#size-cells属性就表示在每个字段中有多少个cells。也就是说想要准确的解释一个reg属性则需要有母节点的#address-cells和#size-cells值。想要了解这些是如何运行的,让我们将寻址属性添加到device tree样本,从CPUs开始。
CPU寻址
当谈论到寻址是,CPU节点是最简单的例子。每个CPU都有一个单独且唯一的ID,并且没有size与CPU ids相关联。
cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };
在cpus节点,#address-cells被设置成了1,#size-cells被设置成了0。这是说子reg值是单独的uint32,它用无大小字段表示地址。在此情况下,这两个cpu分配到的地址为0和1。Cpu节点的#size-cells是0因为每个cpu只分配到了一个单独的地址。
你仍然需要注意reg值班需要与节点名的值相匹配。按照惯例,如果一个节点有一个reg属性,那么这个节点名称必须包括unit-address,这是reg属性的第一个address值。
内存映射设备
与在cpu节点中单独的address值不同,内存映射设备被分配了一系列将要响应的地址。#size-cells用来表示在每个子reg元组中长度字段的大小。在以下示例中,每个address值为1 cell(32 bits),每个长度值也是1 cell,这在32 bit系统是比较典型的。64 bit设备也许会为#address-cells和#size-cells使用数值2,在device tree中获取64 bit addressing。
/ {
    #address-cells = <1>;
    #size-cells = <1>;
    ...
    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
    };
    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
    };
    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
               0x101f4000 0x0010>;
    };
    interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
    };
    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
    };
    ...
};
非内存映射设备
处理器总线的其它设备为非内存映射设备。他们有地址范围,但不能被CPU直接寻址。母设备的驱动程序将代替CPU进行间接访问。
以i2c设备为例,每个设备都分配了一个地址,但没有长度或范围与之相匹配。这与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>;
            };
        };
欢迎大家提出自己的想法和意见,可以以回复的形式提出,或者加入我的QQ群大家一起交流,互相学习。
      名   称:openwrt开发
      群   号:  79612872
 
 

举报

   
 楼主
|
发表于 2014-8-18 09:28
|
范围(地址转换)
我们已经讨论过如何向设备分配地址,但此时这些地址只是本地设备节点,还没有说明如何从那些地址里映射到cpu可以使用的地址。
根节点经常描述地址空间的CPU视图。根节点的子节点已经使用了CPU的address domain,所以不需要任何明确的映射。例如,serial@101f0000设备被直接分配了地址0x101f0000。
根节点的非直接子节点是无法使用CPU的address domain的。为了在deivce tree获取内存映射地址必须指定如何从一个域名将地址转换到另一个。Ranges属性就用于此目的。
以下是添加了ranges属性的device tree示例。
/ {
    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-cell值和子地址的#size-cells值而定。以外部总线为例,子地址是2 cells,母地址是1 cell,大小也为1 cell。转换三个ranges:
        Offset 0 from chip select 0 被映射到address range 0x10100000..0x1010ffff
        Offset 0 from chip select 1被映射到address range 0x10160000..0x1016ffff
        Offset 0 from chip select 2被映射到 address range 0x30000000..0x10000000
轮流的,如果母地址或子地址空间是唯一的,那么一个节点可以添加一个空ranges属性。一个空ranges属性的出现表示位于子地址空间的地址被1:1的映射到母地址空间。
你也许要问为什么当地址可以被1:1映射的时候还要使用地址转换。一些总线(如PCI)拥有完全不同的地址空间,而这些地址空间细节需要出现在操作系统。其它则拥有DMA驱动程序,这些程序需要在总线了解真正的地址。有时设备需要被集合,因为他们都分享相同的软件可编程物理地址映射。
你需要注意的是在i2c@1,0节点中没有ranges属性。原因是与外部总线不同,i2c总线的设备在cpu地址域名没有内存映射。而是cpu通过i2c@1,0设备间接访问rtc@58设备。缺少ranges属性意味着一个人设备除了线设备之外,不允许任何设备进行直接访问。
如何中断运行
与遵循自然树结构的地址范围转换不同,中断信号可以源自于或终止于一个机器的任何设备。与树结构中自然传递的设备地址不同,中断信号只在树结构中的独立节点间传递。四个属笥用于描述中断联接:
        Interrupt-controller-一个空属性表明一个节点作为一个接收中断信号的设备
        #interrupt-cell-这是中断控制器节点的一个属性。它代表此中断控制器的interrupt specifier有多少cells。
        Interrupts-包括interrupt specifier列表设备的一个属性,设备上每个中断输出信号都有一个。
一个interrupt specifier数据的是一个或多个cell,此数据表示此设备附属于哪个中断输入。大多数设备只有一个单独的中断输出,如下面示例,但设备上也可能有多个中断输出。一个中断说明符表达的意思完全取决于与中断控制器设备的捆绑。每个中断控制器都可以决定唯一识别中断输入的所需的cell量。
以下代码向我们Coyote’s Revenge样机添加了中断连接:
/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&intc>;
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };
    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
        interrupts = < 1 0 >;
    };
    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
        interrupts = < 2 0 >;
    };
    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
               0x101f4000 0x0010>;
        interrupts = < 3 0 >;
    };
    intc: interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
        interrupt-controller;
        #interrupt-cells = <2>;
    };
    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
        interrupts = < 4 0 >;
    };
    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>;
            interrupts = < 5 2 >;
        };
        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            interrupts = < 6 2 >;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
                interrupts = < 7 3 >;
            };
        };
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};
注意事项:
        此样机拥有一个单独的中断控制器,interrupt-controller@10140000。
        “intc:”标签被添加到了中断控制器节点,并且用于向根节点的interrupt-parent属性分配一个phandle。此interrupt-parent值成了系统的默认值。
        每个设备都使用一个中断属性来指定一个不同的输入线
        #interrupt-cell是2,所以每个中断说明符拥有2个cell。
欢迎大家提出自己的想法和意见,可以以回复的形式提出,或者加入我的QQ群大家一起交流,互相学习。
      名   称:openwrt开发
      群   号:  79612872
 
 

举报

   
 楼主
|
发表于 2014-8-25 09:41
|
设备具体数据
除了通用的属性以外,任意属性和子节点都能添加到节点。任何操作系统需要的数据只要有一些规则就可以进行添加。
首先,新device-specific属性名称应该使用一个制造商前缀,这样它们才不会与已存在标准属性名称相冲突。
其次,属性和子节点代表的意义必须有绑定的说明,这样设备驱动程序开发者才能了解如何中断数据。一个绑定的文档能常包括特殊兼容值含义,应该有哪些属性,可能存在的子节点和代表的是什么设备。每个唯一的compatible值都应该有它自己的绑定文档。新设备的绑定文档应该在wiki。
第三,将新的绑定文档放在邮件列表中。查看新的绑定文档来获取将来可能会发生的常见问题。
特殊节点
aliases节点
一个特定的节点通常由全路径引用,如/external-bus/ethernet@0,0,但当用户想知道具体内容的时候显得太累赘,“哪个设备是eth0?”。Aliases邛咪可以用来为设备全路径分本一个短的ALIAS。如:
aliases {
        ethernet0 = &eth0;
        serial0 = &serial0;
    };
当为设备分配一个标识符的时候,操作系统更倾向于使用aliases。
你会注意到这里使用的新句法。Property = &label;句法分配了由用作字符串属性的label引用的完整节点路径。这与phandle = < &label >不同;
chosen节点
chosen节点不代表一个真正的设备,但功能与在固件和操作系统间传递数据的地点一样,如根参数。位于chosen节点的数据不代表硬件。具有代表性的是在in.dts源文件中值为空。
在我们的示例系统中,固件也许添加了以下的chosen节点:
chosen {
        bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
    };
高级主题
高级样机
现在我们了解了基本定义,那么我们就向样机添加一些固件来讨论一些更加复杂的情况。
高级样机使用控制寄存器内存映射0X101180000来添加PCI主机桥,并执行BARs来启动以上的地址0x80000000。
给出我们已经了解的关于device tree的内容。我们就可以从以下附加的节点来描述PCI主机桥了。
pci@10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
        };
PCI主机桥
此节描述了Host/PCI桥节点。
注意的是,一些关于PCI的基本知识。这不是关于PCI的指南,如果你需要一些更深入的信息,请读[1]。
PCI总线编号
每个PCI总线段都有唯一编号,并且总线编号是通过使用bus-ranges属性显示出来的,此属性包括2个cell。第一个cell会将分配到此节点的总线编号,第二个cell会给出任何一个PCI总线下级当中最高线线编号。
此样机拥有一个单独的pci总线,所以两个cell都为0。
pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-ranges = <0 0>;
        };
PCI地址转换
与之前讨论过的本地总线相似,PCI地址空间从CPU地址空间中完全分离出去了,所以需要从PCI址址到CPU地址进行地址转换。通常情况会使用rang,#address-cells和size-cells属性来完成。
pci@0x10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
            bus-ranges = <0 0>;
            #address-cells = <3>
            #size-cells = <2>;
            ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
                      0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
                      0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
        };
正如你所看到的,子地址(PCI地址)使用了3个cell,PCI range被编入了2个cell。首先的问题可能是为什么我们需要3个32 bit cell来指定PCI地址。这三个cell被标记成phys.hi.mid和phys.low。
        phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr
        phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
        phys.low cell: llllllll llllllll llllllll llllllll
PCI地址宽度是64 bi,并且都编入到phys.mid和phys.low。然而真正有趣的事是在1 bit字段的phys.high:
        n: 可再定址的地区标记(在这里无效)
        p: 可预取地址标记
        t: 别名地址标记(此处无效)
        ss: 空间代码
        00: 配置空间
        01: I/O空间
        10:32 bit 内存空间
        11:64 bit 内存空间
        Bbbbbbbb: PCI总线编号。PCI也许是分等级的结构。所以我们也许需要有PCI/PCI桥来定义子总线。
        Ddddd: 设备编号,通常与IDSEL信号连接相匹配。
        Fff: 功能编号。用于多功能PCI设备。
        Rrrrrrr: 寄存器编号,用于设置周期。
为了进行PCI地址转换,最重要的字段是p和ss。位于phys.hi的P和ss的值确定了访问哪个PCI地址空间。所以查看我们的ranges属性,我们有3个区域:
        一个32 bit可预取内存区域,它位于512MByte size的PCI地址0x80000000,并且将映射到主机CPU的地址0x80000000。
        一个32 bit非可预取内存区域,它位于256MByte size的PCI地址0xa0000000,并且将映射到主机CPU的地址0xa0000000。
        一个I/O区域,它位于16MByte size的PCI地址0x0000000,并且将会映射到主机CPU地址0x0000000。
此phys.hi位字段的存在表示一个操作系统需要知道节点代表了一个PCI桥,这样它才能忽略不相干的字段实现转换。一个OS将在PCI总线节点查询字符串“pci”来决定它是否需要掩饰额外的字段。

转载地址:https://blog.csdn.net/yyyyyyyyyywwwwwwwwww/article/details/44152449 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:修改rt5350 openwrt的 mac地址
下一篇:Linux芯片级移植与底层驱动(基于3.7.4内核)

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月04日 18时07分56秒