DSP

pci与AHB

2019-07-13 19:59发布

摘自:http://www.embeddedlinux.org.cn/bbs/htm_data/9/0809/109.html
简单总结一下PCI总线编程,需要的时候翻起来看看,省得忘记了。 以IXP455,rtl8139为例子,介绍一下怎么配置使用。参考的资料有,IXP455/IXP465 datasheet, rtl8139d datasheet, PCI2.1 规范,以及网上的点点滴滴。 基本的概念
PCI地址空间分为memory space, I/O space, 和 configuration space。这个是PCI总线编程必须搞清楚的,为了实现plug&play,把这些东西搞进来,不用再象以前的ISA总线那样,搞几个拨码开关来设置基地址。完全通过软件配置自动就可以把PCI总线的设备配置好。
Memory space 和 I/O space 可以通过相应的BAR(基址寄存器)寄存器来体现出来。 Configuration Space是PCI特有的,需要专门的C/BE(Command Byte Enable)命令字去访问。
每一个PCI总线设备必须包含Configuration Space,其内容如下:
软件可以通过查询PCI设备的Device ID 和vendor ID来确定是否有设备插入。把configuration配置空间配置好了,PCI设备就像一般的内存(I/O)映射设备那样工作了。具体就是配置好BAR。 
还要注意的几个PIN,一个是四个PCI的中断PIN,INTA,INTB,INTC,INTD,看它是和CPU的interrupt controller 怎么连的。了解Interrupt Line的含义和用法,就是读出来,然后交给系统,换回来一个系统中断号,然后你可以写自己的中断处理程序了。那么是谁写进去的?PC机的话,是BIOS程序会去做,嵌入式系统,就在bootloader写进去就可以了。具体写什么要看硬件连接。
二是ID_SEL这个PIN,它是用来选择从设备的,就是选择PCI总线上某个设备,ID_SEL很可能是来自某根地址/数据线(A/D)。或者某种逻辑组合,完全由硬件设计决定。PCI规范没有强求。
 
系统配置
IXP455处理器作为PCI host,RTL8139作为PCI设备。IXP455的INTA PIN连接到IXP455的GPIO 6,GPIO6可以用作中断源,电平中断,INTB连接到GPIO7,INTC连接到GPIO8,INTD连接到GPIO9。ID_SEL直接用AD_22。
关于ID_SEL,PCI2.1上的解释是
ID_SEL:Initialization Device Select is used as a chip select during configuration read and write 
transactions.
只是在读写配置空间的时候用。
RTL8139的INT PIN寄存器读出来是0x01,使用的是INTA。这里假设在RLT8139所在的插槽经过某个算法,得出INTA是连接到GPIO6的。关于分配这几个GPIO做为中断的算法,PCI 2.1上有个简单的提议,基本上LINUX上的分配也是这样的。稍后讨论。
 
IXP455: XSCALE系列。PCI的配置有如下:
PCI_AHBMEMBASE寄存器。
PCI_AHBIOBASE寄存器
PCI_PCIMEMBASE寄存器
5个BAR寄存器
CSR寄存器,通过操作它来访问自己的配置空间或者总线上其他设备的配置空间。还可以查一些状态。 
IXP455的4个地址空间用于PCI空间,就是0x48000000-0x48ffffff, 0x49000000-0x49ffffff, 0x4a000000-
0x4affffff,0x4b000000-0x4bffffff。每个空间16MB,这个空间指的是ARM自己AHB总线上的空间。也就是当ARM发出这个地址指令的时候会送到PCI controller,PCI controller怎么工作,要看配置了。
 
RTL8139, MEMBAR寄存器,位于配置空间的0x14处。
参考下图的连接:
 

Figure 1,连接示意图
 
配置过程:
IXP455 Host 配置部分
1.  IXP455的硬件配置(管脚配置)成host模式。
2.  通过AHB配置自身的配置空间,主要是设置BAR寄存器。对于IXP455来说,配置自身的配置空间可以是使用一组称为PCI Configuration Port Address Command/Byte Enable寄存器来配置。
从上图我们可以看出,PCI空间和AHB空间是不一样的,也就如果数据由PCI到AHB,我们称之为,INBOUND,那么PCI的地址必须转为AHB的地址,这样CPU才能认识。这个由几个寄存器决定,1,BAR寄存器,2,PCI_AHBMEMBASE.(这里讨论的是memory空间,IO的也一样,只是有些CPU是没有IO空间的,所以都映射为MEMORY)。
设置BAR0~BAR4为:
BAR0: 0xA0000000
BAR1: 0xA1000000
BAR2: 0xA2000000
BAR3: 0xA3000000
BAR4: 0xA4000000 (硬件设置直接映射到CSR)
BAR5: 0xA5123400 (I/O支持256字节) 
设置PCI_AHBMEMBASE=0x00010203 
这个设置的意思是,从PCI过来的地址,如果命中了BAR0~BAR3的范围,那么这个地址经过翻译后送到AHB总线。
假设,PCI总线上的另一个设备发起读操作,需要读取IXP455的内存地址在0x10000000-0x100000ff的256个字节,那么这个设备必须要在PCI总线上产生0xA1000000到0xA10000ff的地址。
当总线上产生了0xA1000000的地址的时候,正好命中BAR1,而PCI_AHBMEMBASE为0x00010203,那么这个地址转换到AHB空间的时候被PCI_AHBMEMBASE的23-16bit把高8bit替换,所以访问的物理地址就是AHB空间的0x01000000。
其中PCI_AHBMEMBASE的高31-14是针对BAR0,
23-16针对BAR1,15-8正对BAR2,7-0针对BAR3 
配置了BAR和PCI_AHBMEMBASE,主要是针对外部的设备访问自身的。
下一步该配置怎么去访问外面的设备。 
3,配置好寄存器PCI_PCIMEMBASE.
这里我们假设配置PCI_PCIMEMBASE=0xC1C2C3C4,它分别对应CPU映射给PCI的四个段,0x48000000到0x4bffffff。
假设,我们希望访问某个PCI外设,通过0x48000000-0x48ffffff来访问。
那么ARM发出地址为0x48123456,AHB地址,直接落到了PCI window的第一个窗口,那么经过翻译,就是把PCI_PCIMEMBASE的最高8bit替换了AHB的高8bit,那么就会在PCI总线上产生0xC1123456的PCI地址。
其中PCI_PCIMEMBASE的31-24针对PCI window的第一个窗口,以此类推。 
到这里,PCIhost的配置基本结束了。
配置device RTL8139,
1.       通过CBE配置好RTL8139的MEMBAR寄存器。这是PCI相关的最基本工作。其他的都是业务相关的配置。
MEMBAR位于配置空间的0x14h处,那么我们发起一个CBE命令,向0x14操作。
如何保证能选取到RTL8139设备呢?就是ID_SEL这根PIN,而根据我们的硬件假设,它就是AD_22,那么就在发起命令要填如的AD地址时,保证AD_22=1。我们写的地址是0x14,所以填入CBE寄存器组中,AD寄存器就是0x00400014。
操作过程分两步,第一是写入全1到0x14,然后再读取,设备会告诉host需要多少空间,具体怎么告诉,PCI2.1由详细介绍,就是看有几个0,具体设备RTL8139,需要256字节的memory空间。
 
那么这个BAR究竟应该填入什么呢?这个就是PCI的memory资源的分配问题。假设这是第一个被发现的设备,我们就映射到第一个IXP455 PCI window,也就是0X48000000的IXP455 AHB空间。又因为从AHB到PCI的转换是转到了0xC1000000的空间范围,而且RTL8139只需要256字节的空间,那我们可以设置,BAR=0xC1000000,那么在0xC1000000 
– 0xC10000ff都可以访问到RTL8139的内存映射空间。