硬件确认OK后,U-BOOT应该可以看到预期的PCIE1控制器枚举到需要的设备
PCIe1: Root Complex of mini PCIe SLOT, x1, regs @ 0xffe0a000
01:00.0 - 1095:3132 - Mass storage controller
PCIe1: Bus 00 - 01
PCIe2: Root Complex of PCIe SLOT, no link, regs @ 0xffe09000
PCIe2: Bus 02 - 02
U-BOOT是依靠头文件的宏配置,来确定初始化需要的基本信息的,不像内核要依赖设备树,所以U-BOOT对于硬件调试很重要。那么U-BOOT是如何枚举到PCIE1下面的sata控制器的呢。
首先看一下函数调用路线
board_init_r(board.c)
--->pci_init(drivers/pci/pci.c)
--->pci_init_board(boar/freescale/p1_p2_rdb/pci.c)
--->fsl_pcie_init_board(drivers/pci/fsl_pci_init.c)
--->fsl_pcie_init_ctrl(drivers/pci/fsl_pci_init.c)
-->fsl_configure_pcie(drivers/pci/fsl_pci_init.c)
关键的调用是fsl_pcie_init_ctrl和fsl_configure_pcie
重点看一下这两个函数
int fsl_pcie_init_board(int busno)
{
struct fsl_pci_info pci_info;
ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
u32 devdisr;
u32 *addr;
#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
addr = &gur->devdisr3;
#else
addr = &gur->devdisr;
#endif
devdisr = in_be32(addr);
#ifdef CONFIG_PCIE1
SET_STD_PCIE_INFO(pci_info, 1);
busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE1, &pci_info);
#else
setbits_be32(addr, _DEVDISR_PCIE1); /* disable */
#endif
#ifdef CONFIG_PCIE2
SET_STD_PCIE_INFO(pci_info, 2);
busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE2, &pci_info);
#else
setbits_be32(addr, _DEVDISR_PCIE2); /* disable */
#endif
#ifdef CONFIG_PCIE3
SET_STD_PCIE_INFO(pci_info, 3);
busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE3, &pci_info);
#else
setbits_be32(addr, _DEVDISR_PCIE3); /* disable */
#endif
#ifdef CONFIG_PCIE4
SET_STD_PCIE_INFO(pci_info, 4);
busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE4, &pci_info);
#else
setbits_be32(addr, _DEVDISR_PCIE4); /* disable */
#endif
return busno;
}
可以看到如果有需要的话,会对每个PCIE控制器进行初始化设置,
设置的开始首先是设定PCI控制器的基本寄存器位置,这些位置在U-BOOT里通过头文件宏来提供,linux使用DTB获取。
看一下宏SET_STD_PCIE_INFO就一目了然了
#define SET_STD_PCIE_INFO(x, num)
{
x.regs = CONFIG_SYS_PCIE##num##_ADDR;
x.mem_bus = CONFIG_SYS_PCIE##num##_MEM_BUS;
x.mem_phys = CONFIG_SYS_PCIE##num##_MEM_PHYS;
x.mem_size = CONFIG_SYS_PCIE##num##_MEM_SIZE;
x.io_bus = CONFIG_SYS_PCIE##num##_IO_BUS;
x.io_phys = CONFIG_SYS_PCIE##num##_IO_PHYS;
x.io_size = CONFIG_SYS_PCIE##num##_IO_SIZE;
x.law = LAW_TRGT_IF_PCIE_##num;
x.pci_num = num;
}
U-BOOT获取了相应的寄存器位置后,就会配置对应的PCIE控制器
int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
struct fsl_pci_info *pci_info)
{
struct pci_controller *hose;
int num = dev - PCIE1;
hose = calloc(1, sizeof(struct pci_controller));
if (!hose)
return busno;
if (is_serdes_configured(dev) && !(devdisr & devdisr_mask[num])) {
busno = fsl_configure_pcie(pci_info, hose,
board_serdes_name(dev), busno);
} else {
printf("PCIe%d: disabled
", num + 1);
}
return busno;
}
端口硬件禁能的会输出printf("PCIe%d: disabled
", num + 1);
硬件使能的,开始fsl_configure_pcie枚举控制器
int fsl_configure_pcie(struct fsl_pci_info *info,
struct pci_controller *hose,
const char *connected, int busno)
{
int is_endpoint;
set_next_law(info->mem_phys, law_size_bits(info->mem_size), info->law);
set_next_law(info->io_phys, law_size_bits(info->io_size), info->law);
is_endpoint = fsl_setup_hose(hose, info->regs);
printf("PCIe%u: %s", info->pci_num,
is_endpoint ? "Endpoint" : "Root Complex");
if (connected)
printf(" of %s", connected);
puts(", ");
return fsl_pci_init_port(info, hose, busno);
}
函数的最后调用,枚举总线。
fsl_pci_init_port
->fsl_pci_init
->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;
#ifndef CONFIG_PCI_PNP
struct pci_config_table *cfg;
#endif
pci_dev_t dev;
#ifdef CONFIG_PCI_SCAN_SHOW
static int indent = 0;
#endif
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)
continue;
if (!PCI_FUNC(dev))
found_multi = header_type & 0x80;
debug("PCI Scan: Found Bus %d, Device %d, Function %d
",
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);
#ifdef CONFIG_PCI_SCAN_SHOW
indent++;
/* Print leading space, including bus indentation */
printf("%*c", indent + 1, ' ');
if (pci_print_dev(hose, dev)) {
printf("%02x:%02x.%-*x - %04x:%04x - %s
",
PCI_BUS(dev), PCI_DEV(dev), 6 - indent, PCI_FUNC(dev),
vendor, device, pci_class_str(class >> 8));
}
#endif
#ifdef CONFIG_PCI_PNP
sub_bus = max(pciauto_config_device(hose, dev), sub_bus);
#else
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);
}
#endif
#ifdef CONFIG_PCI_SCAN_SHOW
indent--;
#endif
if (hose->fixup_irq)
hose->fixup_irq(hose, dev);
}
return sub_bus;
}