PowerPC的PCI总线的dts配置【转】

本文深入解析 PowerPC 架构下 Linux 的移植过程,重点介绍了扁平设备描述树 (FDT) 的工作原理及其在 PCI 总线配置中的应用。通过具体实例,详细解释了 dts 文件中 ranges 和 interrupt-map 属性的含义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

powerpc使用称为FDT 扁平设备描述树的机制传递给内核硬件配置参数,从而引导内核。 这样的优势是PowerPC在Linux上的移植基本上都是对dts文件的修改,而升级内核的工作量远远小于其他cpu体系结构。

只是目前介绍FDT或者OPEN Firmware的中文资料欠缺,这里记录我领悟的关于PCI总线树部分的ranges参数。


pci0: pci@e0008500 {
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IRQ5 = 21 = 0×15, IRQ6 = 0×16, IRQ7 = 23 = 0×17 */

/* IDSEL AD14 IRQ6 inta */
0×7000 0×0 0×0 0×1 &ipic 0×12 0×8
/* IDSEL AD15 IRQ5 inta, IRQ6 intb, IRQ7 intd */
0×7800 0×0 0×0 0×1 &ipic 0×13 0×8
>;

interrupt-parent = <&ipic>;
interrupts = <66 0×8>;
bus-range = <0×0 0×0>;

ranges = <0×02000000 0×0 0×90000000 0×90000000 0×0 0×10000000
0×42000000 0×0 0×80000000 0×80000000 0×0 0×10000000
0×01000000 0×0 0×00000000 0xe0300000 0×0 0×00100000>;
sleep = <&pmc 0×00010000>;
clock-frequency = <66666666>;
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0xe0008500 0x100        /* internal registers */
0xe0008300 0×8>;        /* config space access registers */
compatible = “fsl,mpc8349-pci”;
device_type = “pci”;
};


这是一个mpc8379的dts配置文件,一些属性还是很好理解,
pci@e0008500说明这个pci控制器的寄存器映射基地址为e0008500
reg = <0xe0008500 0x100        /* internal registers */
0xe0008300 0×8>;        /* config space access registers */
再次证明,pci控制器的寄存器映射基地址为e0008500,读取配置空间使用的寄存器映射基址为0xe0008300,后面是长度,8个字节。即CFG_ADDR和CFG_DATA这两个寄存器。

最最费解的是ranges,用来描述cpu地址空间和pci地址空间的映射关系。
对于e300内核来说,一组配置由6个32位16进制组成。


ranges =
<0×02000000 0×0 0×90000000 0×90000000 0×0 0×10000000
0×42000000 0×0 0×80000000 0×80000000 0×0 0×10000000
0×01000000 0×0 0×00000000 0xe0300000 0×0 0×00100000>;


这里有3组,开头的第一个32位数表明映射的地址的属性。0x01000000是IO映射,0x02000000是内存映射,0x42000000也是内存映射,支持预取。
第2-3个双字表示pci总线的地址空间,用2个双字因为PCI总线可能是支持64位寻址的。
第4个双字表示放cpu_address ,即cpu存储器域地址空间,是cpu寻址的空间。e300是32位cpu,如果是e500内核,则需要2个双字了。
第5-6个双字表示映射长度

内核启动消息里显示


mpc837x_rdb_setup_arch()
Found FSL PCI host bridge at 0x00000000e0008500. Firmware bus number: 0->0
PCI host bridge /pci@e0008500 (primary) ranges:
MEM 0×0000000090000000..0x000000009fffffff -> 0×0000000090000000
MEM 0×0000000080000000..0x000000008fffffff -> 0×0000000080000000 Prefetch
IO 0x00000000e0300000..0x00000000e03fffff -> 0×0000000000000000


正好与之匹配。

分配配置空间要注意cpu存储器域地址空间,不要跟其他设备的cpu存储器域地址空间重复。

************************************************************************************************************

/* IPIC

               * interrupts cell = <intr #, sense>

               * sense values match linux IORESOURCE_IRQ_* defines:

               * sense == 8: Level, low assertion

               * sense == 2: Edge, high-to-low change

               */

              pic@700 {

                     linux,phandle = <700>;         --->节点标记号

                     interrupt-controller;          --->表明为中断控制器

                     #address-cells = <0>;

                     #interrupt-cells = <2>;          --->表示响应边缘触发的中断(由高电平到低电平)

                     reg = <700 100>;          --->中断控制器IMMR的偏移量以及大小

                     built-in;

                     device_type = "ipic";            --->设备类型:Integrated Programmable Interrupt Controller

              };

 

 

              pci@8500 {

                     interrupt-map-mask = <f800 0 0 7>;

                            ---> interrupt-map-mask由unit address mask以及

                                interrupt specifier mask两部分组成,每部分

                                占cells的个数分别由#address-cells与#interrupt-cells

                                决定。

 

                     interrupt-map = <

                                   /* IDSEL 0x0E -mini PCI */

                                    7000 0 0 1 700 12 8

                                    7000 0 0 2 700 12 8

                                    7000 0 0 3 700 12 8

                                    7000 0 0 4 700 12 8

 

                                   /* IDSEL 0x0F - PCI slot */

                                    7800 0 0 1 700 11 8

                                    7800 0 0 2 700 12 8

                                    7800 0 0 3 700 11 8

                                    7800 0 0 4 700 12 8>;

                            ---> interrupt-map 表示每个PCI设备中断与IPIC之间的对应关系

                                    如下:

                                    7000 0 0

                                    表示unit address,由#address-cells决定其大小,其值

                                    为<7000 0 0> & <f800 0 0>(位与)取高5位得到0x0e,对应该PCI

                                    设备的IDSEL AD值;

                                             1

                                    表示该PCI设备的INTA跨接PCI 中断控制器的INTX。每个

                                    PCI设备有INTA、INTB、INTC以及INTD四个硬件中断(

                                    对应数值为1、2、3以及4),该值表示该PCI设备与PCI

                                   Controller相连的硬件中断引脚。

                                              700

                                    表示所应该连接的中断控制器的标记号

                                                  11 8

                                    表示占用中断控制器(如IPIC Controller)向量值,即为

                                    interrupt specifier值,8表示电平触发;

 

                     interrupt-parent = <700>;

                     interrupts = <42 8>;             

                            ---> interrupts由两部分组成interrupt specifier值(66),

                                 以及interrupt type/sense(8, 表示电平触发)。

                     bus-range = <0 0>;

                     ranges = <02000000 0 90000000 90000000 0 10000000

                               42000000 0 80000000 80000000 0 10000000

                               01000000 0 00000000 e2000000 0 00100000>;

                            ---> rangs由bus address, parent bus address, size三部分组成;

                                 其每一部分占#size-cells个cells。

                                 bus address, 表示占用总线的地址范围,如PCI Bridge设备,

                                 它就表示一个PCI地址。(bus address, size)定义了PCI Bridge

                                 下游PCI子设备所占用的PCI地址范围;

                                 parent bus address, 表示该总线在父总线上的地址,如PCI控制

                                 器, 它则表示CPU BUS的地址;它定义了父总线上MAP该设备

                                 的起始地址。

 

                     clock-frequency = <3f940aa>;

                     #interrupt-cells = <1>; ---> 表示interrupt specifier占一个cell

                     #size-cells = <2>;   ---> 表示rangs每一个值占两个cells

                     #address-cells = <3>;     ---> 表示unit address 占三个cells

                     reg = <8500 100>;

                     compatible = "83xx";

                     device_type = "pci";

                     sleep = <b00 1 8 00010000 0>;

              };

 

 

              /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */

              --->USB PHY四种类型:

                     ULPI为外置PHY接口,可用于OTG模式

                     UTMI为内置8位数据宽度的PHY接口

                     UTMI_WIDE为内置16位数据宽度的PHY接口

                     SERIAL为串行接口

 

              usb@23000 {

                     device_type = "usb";

                     compatible = "fsl-usb2-dr";   --->dr dual-role,可以充当两个角色:设备和主控制器

                     reg = <23000 1000>;

                     #address-cells = <1>;

                     #size-cells = <0>;

                     interrupt-parent = <700>;

                     interrupts = <26 2>;

                     phy_type = "utmi_wide";

                     control_init  = <00000280>; // UTMI ext 48 MHz clk

                     sleep = <b00 1 8 00300000 0>;

              };

 

 

注:一般来说,  每个cell占用32位

              #address-cells = <1>; 1表示地址32位,2表示地址64位

              #size-cells = <1>;   1表示rangs的每部分占一个cell,依此类推

              #interrupt-cells = <2>; 2表示interrupts用两个cell表示中断<interrupt number, interrupt type>

             


*****************************************************************************************************


Open Firmware 的API函数
  OF提供了许多API,查找保存在全局链表allnodes中的device node。这些API函数的源代码
见./arch/powerc/kernel/prom.c文件。其主要API如下所示:
of_get_flat_dt_root函数。该函数用来查找在dtb中的根节点。 
of_find_node_by_path函数。该函数根据deice_node结构的full_name参数,在全局链表allnodes中,查找合适的device_node。该函数的使用方法如下所示:    

struct device_node *cpus; 
    cpus=of_find_node_by_path("/cpus");


of_find_node_by_name函数。该函数的使用方法如下所示:

struct device_node *np; 
np = of_find_node_by_name(NULL,"firewire"); 


 如果of_find_node_by_name函数的第一个参数为NULL,该函数根据device_node结构的name参数,在全局链表allnodes中查找合适的device_node.
of_find_node_by_type函数。该函数的使用方法如下所示:

struct device_node *tsi_pci; 
tsi_pci= of_find_node_by_type(NULL,"pci"); 

 如果of_find_node_by_name函数的第一个参数为NULL,该函数根据device_node结构的type参数,在全局链表allnodes中查找合适的device_node.
of_find_node_by_phandle函数。该函数的使用方法如下所示: 

struct device_node *phy; 
phy = of_find_node_by_phandle(*ph); 


上述这些函数根据device_node结构的相应参数,寻找到合适的device_node之后,可以使用以下函数寻
找device_node结构中相应的分项。
of_find_property函数。该函数根据property结构的name参数,在指定的device node中查找合适的property。该函数的使用方法如下: 

struct device_node *np; 
const char *name; 
int *lenp; 
struct property *pp=of_find_property(np,name,lenp); 


of_address_to_resource,of_get_address 函数。这两个函数对指定的device node结构进一步分解,以获得指定的分项。这两个函数在./arch/powerpc/kernel/prom_parse.c文件中定义。在该文件中还有一系列用来分解pci节点和pic节点的一些专用函数,其中pci节点与PCI总线的配置有关,而pic节点与PCI中断控制器有关。

本文转自:http://www.360doc.com/content/11/0304/14/3038654_98052547.shtml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值