p1020&pcie&u-boot&枚举

话不多说,继续u-boot代码的pcie枚举。先贴代码:


void mpc85xx_serdes_board_init(void)
{
volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
struct fsl_pci_info pci_info[3];
u32 devdisr, host_agent;
int first_free_busno = 0;
int num = 0;
int rio = 0;


int pcie_ep;


devdisr = in_be32(&gur->devdisr);
host_agent = (in_be32(&gur->porbmsr) & MPC85xx_PORBMSR_HA) >> 16;


debug("   mpc85xx_serdes_board_init: devdisr=%x, host_agent=%x\n",
devdisr, host_agent);


if (!(gur->pordevsr & MPC85xx_PORDEVSR_SGMII1_DIS)) {
if (is_serdes_configured(SGMII_TSEC1))
puts("    eTSEC1 is in sgmii mode.\n");
}
if (!(gur->pordevsr & MPC85xx_PORDEVSR_SGMII2_DIS)) {
if (is_serdes_configured(SGMII_TSEC2))
puts("    eTSEC2 is in sgmii mode.\n");
}
if (!(gur->pordevsr & MPC85xx_PORDEVSR_SGMII3_DIS)) {
if (is_serdes_configured(SGMII_TSEC3))
puts("    eTSEC3 is in sgmii mode.\n");
}


puts("\n");
#ifdef CONFIG_PCIE1
pcie_ep = is_fsl_pci_agent(LAW_TRGT_IF_PCIE_1, host_agent);


if (is_serdes_configured(PCIE1) && !(devdisr & MPC85xx_DEVDISR_PCIE)) {
set_next_law(CONFIG_SYS_PCIE1_MEM_PHYS,
law_size_bits(CONFIG_SYS_PCIE1_MEM_SIZE),
LAW_TRGT_IF_PCIE_1);
set_next_law(CONFIG_SYS_PCIE1_IO_PHYS,
law_size_bits(CONFIG_SYS_PCIE1_IO_SIZE),
LAW_TRGT_IF_PCIE_1);


SET_STD_PCIE_INFO(pci_info[num], 1);
printf("    PCIE1 used as %s (base addr %lx)\n",
pcie_ep ? "End Point" : "Root Complex",
pci_info[num].regs);
first_free_busno = fsl_pci_init_port(&pci_info[num++],
&pcie1_hose, first_free_busno, pcie_ep);
} else {
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE);
printf("    PCIE1: disabled\n");
}
puts("\n");
#else
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE); /* disable */
#endif


#ifdef CONFIG_PCIE2
pcie_ep = is_fsl_pci_agent(LAW_TRGT_IF_PCIE_2, host_agent);


if (is_serdes_configured(PCIE2) && !(devdisr & MPC85xx_DEVDISR_PCIE2)){
set_next_law(CONFIG_SYS_PCIE2_MEM_PHYS,
law_size_bits(CONFIG_SYS_PCIE2_MEM_SIZE),
LAW_TRGT_IF_PCIE_2);
set_next_law(CONFIG_SYS_PCIE2_IO_PHYS,
law_size_bits(CONFIG_SYS_PCIE2_IO_SIZE),
LAW_TRGT_IF_PCIE_2);


SET_STD_PCIE_INFO(pci_info[num], 2);
printf("    PCIE2 used as %s (base addr %lx)\n",
pcie_ep ? "End Point" : "Root Complex",
pci_info[num].regs);
first_free_busno = fsl_pci_init_port(&pci_info[num++],
&pcie2_hose, first_free_busno, pcie_ep);


} else {
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE2);
printf("    PCIE2: disabled\n");
}
puts("\n");
#else
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE2); /* disable */
#endif


#ifdef CONFIG_PCIE3
pcie_ep = is_fsl_pci_agent(LAW_TRGT_IF_PCIE_3, host_agent);


if (is_serdes_configured(PCIE3) && !(devdisr & MPC85xx_DEVDISR_PCIE3)){
set_next_law(CONFIG_SYS_PCIE3_MEM_PHYS,
law_size_bits(CONFIG_SYS_PCIE3_MEM_SIZE),
LAW_TRGT_IF_PCIE_3);
set_next_law(CONFIG_SYS_PCIE3_IO_PHYS,
law_size_bits(CONFIG_SYS_PCIE3_IO_SIZE),
LAW_TRGT_IF_PCIE_3);


SET_STD_PCIE_INFO(pci_info[num], 3);
printf("    PCIE3 used as %s (base addr %lx)\n",
pcie_ep ? "End Point" : "Root Complex",
pci_info[num].regs);
first_free_busno = fsl_pci_init_port(&pci_info[num++],
&pcie3_hose, first_free_busno, pcie_ep);
} else {
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE3);
printf("    PCIE3: disabled\n");
}
puts("\n");
#else
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE3); /* disable */
#endif


#ifdef CONFIG_SRIO
if (is_serdes_configured(SRIO1) && !(devdisr & MPC85xx_DEVDISR_SRIO)){
set_next_law(CONFIG_SYS_SRIO1_MEM_PHYS,
law_size_bits(CONFIG_SYS_SRIO1_MEM_SIZE),
LAW_TRGT_IF_RIO);


rio = 1;
printf("    SRIO1: enabled\n");
} else {
printf("    SRIO1: disabled\n");
}


if (is_serdes_configured(SRIO2) && !(devdisr & MPC85xx_DEVDISR_SRIO)){
set_next_law(CONFIG_SYS_SRIO2_MEM_PHYS,
law_size_bits(CONFIG_SYS_SRIO2_MEM_SIZE),
LAW_TRGT_IF_RIO_2);


printf("    SRIO2: enabled\n");
} else {
printf("    SRIO2: disabled\n");
if (rio == 0)
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_SRIO);


}
#else
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_SRIO); /* disable */
#endif
}
我们知道p1020的4个lane的serdes可以配置成两个x1的pcie接口和一个sgmii
接口,这些配置是在开机启动读响应引脚的电平,并且写在寄存器中,所以这个函数就是?
技拇嫫髦纒erdes被配置成几个pcie以及几个lane,和几个sgmii
,我们的板子是配置成了两个pcie(x1)和一个串行的sgmii(串行千兆以太网接口)。
set_next_law这个函数就是给pcie配置cpu侧的物理地址,在e500核中ddr,pcie,elbc
,这些都需要写lawar,lawbar这两个寄存器,以确定在ddr,pcie,eblc他们使用CPU
的物理地址空间。主要是都device disable这个寄存器确定,那些接口被enable
。下面来讲fsl_pci_init_port枚举的主线就是这个函数,先贴代码:
int fsl_pci_init_port(struct fsl_pci_info *pci_info,
struct pci_controller *hose, int busno, int pcie_ep)
{
volatile ccsr_fsl_pci_t *pci;
struct pci_region *r;


pci = (ccsr_fsl_pci_t *) pci_info->regs;


if (pcie_ep) {
volatile pit_t *pi = &pci->pit[2];


pci_setup_indirect(hose, (u32)&pci->cfg_addr,
(u32)&pci->cfg_data);
out_be32(&pi->pitar, 0);
out_be32(&pi->piwbar, 0);
out_be32(&pi->piwar, PIWAR_EN | PIWAR_LOCAL |
PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_IWS_4K);


fsl_pci_config_unlock(hose);
return 0;
}


/* on non-PCIe controllers we don't have pme_msg_det so this code
* should do nothing since the read will return 0
*/
if (in_be32(&pci->pme_msg_det)) {
out_be32(&pci->pme_msg_det, 0xffffffff);
debug (" with errors.  Clearing.  Now 0x%08x",
pci->pme_msg_det);
}


r = hose->regions + hose->region_count;


/* outbound memory */
pci_set_region(r++,
pci_info->mem_bus,
pci_info->mem_phys,
pci_info->mem_size,
PCI_REGION_MEM);


/* outbound io */
pci_set_region(r++,
pci_info->io_bus,
pci_info->io_phys,
pci_info->io_size,
PCI_REGION_IO);


hose->region_count = r - hose->regions;
hose->first_busno = busno;


fsl_pci_init(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data);


if (fsl_is_pci_agent(hose)) {
fsl_pci_config_unlock(hose);
hose->last_busno = hose->first_busno;
}


printf("    PCIE%x on bus %02x - %02x\n", pci_info->pci_num,
hose->first_busno, hose->last_busno);


return(hose->last_busno + 1);
}
因为我们的控制器是设置成rc的不是ep所以执行pci_set_region
这个函数,这个函数就是把Outbound中映射的cpu物理地址和pcie的总线地址以及size
先放入hose里面,hose就是pci_control这个结构体的实例,随后会写入outbound
寄存器的,下面我来介绍下pci_control
这个结构体:struct pci_controller {
struct pci_controller *next;


int first_busno;
int last_busno;


volatile unsigned int *cfg_addr;
volatile unsigned char *cfg_data;


int indirect_type;


struct pci_region regions[MAX_PCI_REGIONS];
int region_count;


struct pci_config_table *config_table;


void (*fixup_irq)(struct pci_controller *, pci_dev_t);


/* Low-level architecture-dependent routines */
int (*read_byte)(struct pci_controller*, pci_dev_t, int where, u8 *);
int (*read_word)(struct pci_controller*, pci_dev_t, int where, u16 *);
int (*read_dword)(struct pci_controller*, pci_dev_t, int where, u32 *);
int (*write_byte)(struct pci_controller*, pci_dev_t, int where, u8);
int (*write_word)(struct pci_controller*, pci_dev_t, int where, u16);
int (*write_dword)(struct pci_controller*, pci_dev_t, int where, u32);


/* Used by auto config */
struct pci_region *pci_mem, *pci_io, *pci_prefetch;


/* Used by ppc405 autoconfig*/
struct pci_region *pci_fb;
int current_busno;
};
Next链接的是下一个pcie控制器,firstbus是这个pcie控制器的第一条bus的number,
lastbusno是这个pcie控制器的最后一条bus的number,p1020我们设置成两个pcie
第一个没有接设备,第二个接的是sil3132控制器,所以有两个全局变量pcie1_hose和
pcie2_hose他们都是pci_control结构体类型,因为第一个pcie
没有接设备,所以枚举时只会设置pcie
这个主机控制器,并且配置这个主机控制器的配置空间,所以pcie1_hose的first_busno
和lastbusno都是0,而第二个pcie控制器连接的sil3132控制器,所以会先枚举pcie2
这个主机控制的配置空间,并且也会配置sil3132,所以pcie2_hose的firstbusno就是1
,而lastbusno就是2。 


cfg_addr和cfg_data,这两个保存的是这个pcie控制器的cfg_addr和cfg_data
寄存器的物理地址,这两个寄存器是用来访问ep或者switch的配置空间的,regions
是描述cpu物理空间在pcie总线空间的地址和size的,read_byte下面几个函数即是
pci_hose_read_config_byte,pci_hose_read_config_byte等就是读写ep和switch
配置空间的函数,通过pci_setup_indirect
和一些宏来映射。所以我们就知道如何读写配置空间了,是通过下面的函数:


extern int pci_hose_read_config_byte(struct pci_controller *hose,
    pci_dev_t dev, int where, u8 *val);
extern int pci_hose_read_config_word(struct pci_controller *hose,
    pci_dev_t dev, int where, u16 *val);
extern int pci_hose_read_config_dword(struct pci_controller *hose,
     pci_dev_t dev, int where, u32 *val);
extern int pci_hose_write_config_byte(struct pci_controller *hose,
     pci_dev_t dev, int where, u8 val);
extern int pci_hose_write_config_word(struct pci_controller *hose,
     pci_dev_t dev, int where, u16 val);
extern int pci_hose_write_config_dword(struct pci_controller *hose,
      pci_dev_t dev, int where, u32 val);
hose指的就是pcie控制器,dev包含bus,device,function,所以就是指的特定设备,
where就是配置空间的那个寄存器,val就是读写值了
void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
{
u16 temp16;
u32 temp32;
int enabled, r, inbound = 0;
u16 ltssm;
u8 temp8, pcie_cap;
volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
struct pci_region *reg = hose->regions + hose->region_count;
pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);


/* Initialize ATMU registers based on hose regions and flags */
volatile pot_t *po = &pci->pot[1]; /* skip 0 */
volatile pit_t *pi = &pci->pit[2]; /* ranges from: 3 to 1 */


u64 out_hi = 0, out_lo = -1ULL;
u32 pcicsrbar, pcicsrbar_sz;


#ifdef DEBUG
int neg_link_w;
#endif


pci_setup_indirect(hose, cfg_addr, cfg_data);


/* Handle setup of outbound windows first */
for (r = 0; r < hose->region_count; r++) {
unsigned long flags = hose->regions[r].flags;
u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1);


flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE;
if (flags != PCI_REGION_SYS_MEMORY) {
u64 start = hose->regions[r].bus_start;
u64 end = start + hose->regions[r].size;


out_be32(&po->powbar, hose->regions[r].phys_start >> 12);
out_be32(&po->potar, start >> 12);
#ifdef CONFIG_SYS_PCI_64BIT
out_be32(&po->potear, start >> 44);
#else
out_be32(&po->potear, 0);
#endif
if (hose->regions[r].flags & PCI_REGION_IO) {
out_be32(&po->powar, POWAR_EN | sz |
POWAR_IO_READ | POWAR_IO_WRITE);
} else {
out_be32(&po->powar, POWAR_EN | sz |
POWAR_MEM_READ | POWAR_MEM_WRITE);
out_lo = min(start, out_lo);
out_hi = max(end, out_hi);
}
po++;
}
}
debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi);


/* setup PCSRBAR/PEXCSRBAR */
pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff);
pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
pcicsrbar_sz = ~pcicsrbar_sz + 1;


if (out_hi < (0x100000000ull - pcicsrbar_sz) ||
(out_lo > 0x100000000ull))
pcicsrbar = 0x100000000ull - pcicsrbar_sz;
else
pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz;
pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar);


out_lo = min(out_lo, (u64)pcicsrbar);


debug("PCICSRBAR @ 0x%x\n", pcicsrbar);


pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS,
pcicsrbar_sz, PCI_REGION_SYS_MEMORY);
hose->region_count++;


/* see if we are a PCIe or PCI controller */
pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);


/* inbound */
inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi);


for (r = 0; r < hose->region_count; r++)
debug("PCI reg:%d %016llx:%016llx %016llx %08x\n", r,
(u64)hose->regions[r].phys_start,
hose->regions[r].bus_start,
hose->regions[r].size,
hose->regions[r].flags);


pci_register_hose(hose);
pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */
hose->current_busno = hose->first_busno;


out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */
out_be32(&pci->peer, ~0x20140); /* Enable All Error Interupts except
* - Master abort (pci)
* - Master PERR (pci)
* - ICCA (PCIe)
*/
pci_hose_read_config_dword(hose, dev, PCI_DCR, &temp32);
temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */
pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32);


if (pcie_cap == PCI_CAP_ID_EXP) {
pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
enabled = ltssm >= PCI_LTSSM_L0;


#ifdef CONFIG_FSL_PCIE_RESET
if (ltssm == 1) {
int i;
debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm);
/* assert PCIe reset */
setbits_be32(&pci->pdb_stat, 0x08000000);
(void) in_be32(&pci->pdb_stat);
udelay(100);
debug("  Asserting PCIe reset @%x = %x\n",
     &pci->pdb_stat, in_be32(&pci->pdb_stat));
/* clear PCIe reset */
clrbits_be32(&pci->pdb_stat, 0x08000000);
asm("sync;isync");
for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) {
pci_hose_read_config_word(hose, dev, PCI_LTSSM,
&ltssm);
udelay(1000);
debug("....PCIe link error. "
     "LTSSM=0x%02x.\n", ltssm);
}
enabled = ltssm >= PCI_LTSSM_L0;


/* we need to re-write the bar0 since a reset will
* clear it
*/
pci_hose_write_config_dword(hose, dev,
PCI_BASE_ADDRESS_0, pcicsrbar);
}
#endif


if (!enabled) {
debug("....PCIE link error.  Skipping scan."
     "LTSSM=0x%02x\n", ltssm);
hose->last_busno = hose->first_busno;
return;
}


out_be32(&pci->pme_msg_det, 0xffffffff);
out_be32(&pci->pme_msg_int_en, 0xffffffff);
#ifdef DEBUG
pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16);
neg_link_w = (temp16 & 0x3f0 ) >> 4;
printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n",
     ltssm, neg_link_w);
#endif
hose->current_busno++; /* Start scan with secondary */
pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
}


/* Use generic setup_device to initialize standard pci regs,
* but do not allocate any windows since any BAR found (such
* as PCSRBAR) is not in this cpu's memory space.
*/
pciauto_setup_device(hose, dev, 0, hose->pci_mem,
    hose->pci_prefetch, hose->pci_io);


if (inbound) {
pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16);
pci_hose_write_config_word(hose, dev, PCI_COMMAND,
  temp16 | PCI_COMMAND_MEMORY);
}


#ifndef CONFIG_PCI_NOSCAN
pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &temp8);


/* Programming Interface (PCI_CLASS_PROG)
* 0 == pci host or pcie root-complex,
* 1 == pci agent or pcie end-point
*/
if (!temp8) {
printf("               Scanning PCI bus %02x\n",
hose->current_busno);
hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno);
} else {
debug("               Not scanning PCI bus %02x. PI=%x\n",
hose->current_busno, temp8);
hose->last_busno = hose->current_busno;
}


/* if we are PCIe - update limit regs and subordinate busno
* for the virtual P2P bridge
*/
if (pcie_cap == PCI_CAP_ID_EXP) {
pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
}
#else
hose->last_busno = hose->current_busno;
#endif


/* Clear all error indications */
if (pcie_cap == PCI_CAP_ID_EXP)
out_be32(&pci->pme_msg_det, 0xffffffff);
out_be32(&pci->pedr, 0xffffffff);


pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16);
if (temp16) {
pci_hose_write_config_word(hose, dev, PCI_DSR, 0xffff);
}


pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
if (temp16) {
pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
}
}
fsl_pci_init_port会调用fsl_pci_init,这个函数进行pcie
设备枚举。这个函数会先设置outbound寄存器,然后设置pcie控制器的配置空间的
PEXCSRBAR寄存器来映射p1020寄存器ccsrbar,映射完就可以控制ccsrbar
了,从而引发中断给cpu,然后设置inbound寄存器,然后读取pcie控制器的配置空间的
PCI_LTSSM寄存器,我们知道pcie设备连接到pcie
控制器时要进行链路训练,设备会经历几个状态,而L0态设备的正常工作状态所以读取
PCI_LTSSM寄存器看设备的状态,如果>=L0
态说明有设备连接,如果不的话就是没有设备连接,因为pcie1
控制器并没有连接设备所以就直接返回,去枚举pcie2控制器,而pcie2
设备连接了sil3132所以PCI_LTSSM寄存器的值肯定>=L0的。所以函数继续下去,
pciauto_prescan_setup_bridge运行到这个函数就是设置pcie2控制器配置空间的
menory_base和memory_limit寄存器同时也会设置PCI_PRIMARY_BUS,PCI_SECONDARY_BUS
,PCI_SUBORDINATE_BUS等,PCI_SUBORDINATE_BUS=0xff
因为我们并不知道这个控制器可以访问的最后一条不是的number。
pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &temp8);读取的temp=0
说明是rc,所以会执行pci_hose_scan_bus,这个函数会继续枚举下面的连接的sil3132
,下面就来枚举busnumber2,busnumber2只有sil3132所以device和function都是0
,下面贴pci_hose_scan_bus代码:
int pci_hose_scan_bus(struct pci_controller *hose, int bus)
{
unsigned int sub_bus, found_multi=0;
unsigned short vendor, device, class;
unsigned char header_type;
struct pci_config_table *cfg;
pci_dev_t dev;


sub_bus = bus;


for (dev =  PCI_BDF(bus,0,0);
    dev <  PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
    dev += PCI_BDF(0,0,1)) {


if (pci_skip_dev(hose, dev))
continue;


if (PCI_FUNC(dev) && !found_multi)
continue;


pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);


pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);


if (vendor != 0xffff && vendor != 0x0000) {


if (!PCI_FUNC(dev))
found_multi = header_type & 0x80;


debug ("PCI Scan: Found Bus %d, Device %d, Function %d\n",
PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev) );


pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);


cfg = pci_find_config(hose, class, vendor, device,
     PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
if (cfg) {
cfg->config_device(hose, dev, cfg);
sub_bus = max(sub_bus, hose->current_busno);
#ifdef CONFIG_PCI_PNP
} else {
int n = pciauto_config_device(hose, dev);


sub_bus = max(sub_bus, n);
#endif
}
if (hose->fixup_irq)
hose->fixup_irq(hose, dev);


#ifdef CONFIG_PCI_SCAN_SHOW
if (pci_print_dev(hose, dev)) {
unsigned char int_line;


pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE,
 &int_line);
printf("        %02x  %02x  %04x  %04x  %04x  %02x\n",
      PCI_BUS(dev), PCI_DEV(dev), vendor, device, class,
      int_line);
}
#endif
}
}


return sub_bus;
}
读取设备配置空间的PCI_VENDOR_ID的值因为是设备所以不可能为0x0000,所以继续函数
pciauto_config_device;
int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
{
unsigned int sub_bus = PCI_BUS(dev);
unsigned short class;
unsigned char prg_iface;
int n;


pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);


switch(class) {
case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
DEBUGF("PCI AutoConfig: Found PowerPC device\n");
pciauto_setup_device(hose, dev, 6, hose->pci_mem,
    hose->pci_prefetch, hose->pci_io);
break;


case PCI_CLASS_BRIDGE_PCI:
hose->current_busno++;
pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->
pci_io);


DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev));


/* Passing in current_busno allows for sibling P2P bridges */
pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
/*
* need to figure out if this is a subordinate bridge on the bus
* to be able to properly set the pri/sec/sub bridge registers.
*/
n = pci_hose_scan_bus(hose, hose->current_busno);


/* figure out the deepest we've gone for this leg */
sub_bus = max(n, sub_bus);
pciauto_postscan_setup_bridge(hose, dev, sub_bus);


sub_bus = hose->current_busno;
break;


case PCI_CLASS_STORAGE_IDE:
pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface);
if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n");
return sub_bus;
}


pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->
pci_io);
break;


case PCI_CLASS_BRIDGE_CARDBUS:
/* just do a minimal setup of the bridge, let the OS take care of the rest */
pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->
pci_io);


DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev));


hose->current_busno++;
break;


#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE)
case PCI_CLASS_BRIDGE_OTHER:
DEBUGF("PCI Autoconfig: Skipping bridge device %d\n",
      PCI_DEV(dev));
break;
#endif
#if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349)
case PCI_CLASS_BRIDGE_OTHER:
/*
* The host/PCI bridge 1 seems broken in 8349 - it presents
* itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_
* device claiming resources io/mem/irq.. we only allow for
* the PIMMR window to be allocated (BAR0 - 1MB size)
*/
DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n");
pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->
pci_io);
break;
#endif
default:
pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->
pci_io);
break;
}


return sub_bus;
}
这个函数会读PCI_CLASS_DEVICE如果是PCI_CLASS_BRIDGE_PCI则继续
pciauto_prescan_setup_bridge和pci_hose_scan_bus下去也就是嵌套下去直到
遇到读的PCI_CLASS_DEVICE是设备,因为我们的是sil3132,所以会执行
pciauto_setup_device这个函数:
void pciauto_setup_device(struct pci_controller *hose,
 pci_dev_t dev, int bars_num,
 struct pci_region *mem,
 struct pci_region *prefetch,
 struct pci_region *io)
{
unsigned int bar_response;
pci_addr_t bar_value;
pci_size_t bar_size;
unsigned int cmdstat = 0;
struct pci_region *bar_res;
int bar, bar_nr = 0;
int found_mem64 = 0;


pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | 
PCI_COMMAND_MASTER;


for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num*4); bar 
+= 4) {
/* Tickle the BAR and get the response */
pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
pci_hose_read_config_dword(hose, dev, bar, &bar_response);


/* If BAR is not implemented go to the next BAR */
if (!bar_response)
continue;


found_mem64 = 0;


/* Check the BAR type and set our address mask */
if (bar_response & PCI_BASE_ADDRESS_SPACE) {
bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK))
  & 0xffff) + 1;
bar_res = io;


DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", bar_nr, (u64)bar_size);
} else {
if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
    PCI_BASE_ADDRESS_MEM_TYPE_64) {
u32 bar_response_upper;
u64 bar64;
pci_hose_write_config_dword(hose, dev, bar+4, 0xffffffff);
pci_hose_read_config_dword(hose, dev, bar+4, &bar_response_upper);


bar64 = ((u64)bar_response_upper << 32) | bar_response;


bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
found_mem64 = 1;
} else {
bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
}
if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
bar_res = prefetch;
else
bar_res = mem;


DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%llx, ", bar_nr, (u64)bar_size);
}


if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) {
/* Write it out and update our limit */
pci_hose_write_config_dword(hose, dev, bar, (u32)bar_value);


if (found_mem64) {
bar += 4;
#ifdef CONFIG_SYS_PCI_64BIT
pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
#else
/*
* If we are a 64-bit decoder then increment to the
* upper 32 bits of the bar and force it to locate
* in the lower 4GB of memory.
*/
pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
#endif
}


cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
}


DEBUGF("\n");


bar_nr++;
}


pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
CONFIG_SYS_PCI_CACHE_LINE_SIZE);
pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
}
这个函数会设置设备的配置空间bar,配置完bar也会写PCI_COMMAND, 
PCI_CACHE_LINE_SIZE,PCI_LATENCY_TIMER。在写bar时会先写0xffffffff
然后读出来以确定bar空间的size。结束的有些仓促,u-boot的枚举就是先枚举pcie
控制器然后再枚举下面的设备,如果是switch
或者桥则先配置它,然后再枚举下面的设备如果是switch
或者是桥则继续,如果是设备则配置空间,然后回溯写switch或者桥的
PCI_SUBORDINATE_BUS,也就是告诉switch或者桥可以访问的最后的bus_number的号码。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在FPGA驱动LM75A时,需要注意以下几点。首先,LM75A是一个温度传感器,它通过I2C总线与FPGA进行通信。因此,在设计驱动程序时,需要确保对I2C总线的访问是原子操作,以避免数据错误或器件损坏。这可以通过使用互斥对象来封装必须连贯操作的时序控制代码来实现\[2\]。 其次,LM75A的器件地址由固定部分和可编程部分组成。固定部分是指定器件类型的部分,对于LM75A来说是1010。可编程部分用于区分在同一I2C总线上挂载的多个LM75A器件,它由3位管脚pin控制,最多支持8个相同的EEPROM器件。因此,在驱动程序中需要正确设置LM75A的器件地址,以确保与目标器件进行正确的通信\[3\]。 综上所述,在FPGA驱动LM75A时,需要注意确保对I2C总线的原子操作和正确设置LM75A的器件地址。这样可以确保驱动程序能够正确地与LM75A进行通信并获取温度数据。 #### 引用[.reference_title] - *1* [freescale QorIQ P1020嵌入式开发流程总结](https://blog.csdn.net/sinat_36544290/article/details/104518699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [uC/OS-II系统开发的6条重要总结](https://blog.csdn.net/DP29syM41zyGndVF/article/details/79990392)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [I2C-FPGA整理](https://blog.csdn.net/qq_41247463/article/details/110228553)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值