主要讲PCI设备的硬件访问方法。
1、PCI的硬件结构
CPU发出的地址是CPU地址,可能是访问底下任何一个设备。地址范围不一样,访问到的外设就不一样。在嵌入式中,通常将4G内存地址空间分成好几个区域,不同的访问分给不同的地址。桥内存控制器会把CPU地址转换成addr_pci。PCI总线上的地址会到达底下的设备。此时就会引入一个问题,谁来相应这个地址(bridge底下挂载着总线,pci总线上有很多pci设备)?
为了解决上述问题,需要去配置每个设备对应的地址范围(对每个设备进行分配固定地址)。首先就要知道每个设备需要多大的地址空间,例如A设备需要1MB,B设备需要2MB等等。驱动程序需要把PCI地址中的某一段分配给这个设备例如A-B。
步骤:
(1)读设备上的配置寄存器,得到设备的种类,得到需要申请的地址大小。如何选中要配置的设备呢?通过IDSEL信号选中设备(初始化的时候应该会对每个issel号扫描一遍)。
(2)驱动程序分配对应大小的PCI地址给设备。
(3)将地址访问写回PCI的配置寄存器。
(4)配置好后就可以像内存一样读写。
图片来自哪里?
2、PCI硬件信号
AD[31:0]地址和数据复用的线,Frame信号用于判断时读还是写:当Frame信号为低的时候,clk信号由低电平变高电平,此时AD上传输的是地址。如下图所示。在后续的时钟例传输的就是data。 注意这里还有个IDSEL信号,是用来配置设备时去选中中设备。
《来自PCI3.0规范手册:PCI Local Bus Specification Revision 3.0》
总线上既有地址又有数据,如何分辨什么时候是数据地址?
在配置的时候,如何正确的选中设备?
如下图所示,当总线上有很多设备时候。一开始的时候,这些设备都没有配置。此时页不知道上面传输的地址信号是用来访问谁的,设备无法做出响应。此时如何进行配置设备。答案是通过IDSEL信号,一般选用AD31-11信号来选中不同的设备(通过不同的引脚来选中设备),所有最多有20个设备。CPU通过AD31引脚选中第一个设备,然后去读它的配置空间的信息。可以得到设备类型,device ID和type等。
如何访问某个配置寄存器?
type0的配置空间的分布如下图。基地址寄存器是在分配好地址空间之后,驱动会把地址范围写到Base Address Register寄存器中。以后设备就可以检测到这些地址属于自己的范围。对于每个设备都有256字节的寄存器。设备可能有多种功能,function(最多8中功能),对于每种功能都有256字节的配置寄存器。此时就涉及到如何选中这个设备中某一个功能了。答案就是用data总线上的0-10位。11-31位刚刚说了用来当IDSEL信号。
《PCI规范手册》
如何选中设备中的某个功能?以及选中某个寄存器?
(1)选中设备,通过IDSEL信号。(2)使用AD[31:0]指定function和register (3)指定读或者写,通过C/BE#信号指定,可以配置配置读配置写,IO读和IO写。(4)基地址寄存器会写入起始地址。