if (!PCI_FUNC(bdf))
found_multi = header_type & 0x80;
- debug("%s: bus %d/%s: found device %x, function %d\n", __func__,
+ debug("%s: bus %d/%s: found device %x, function %d", __func__,
bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
pci_bus_read_config(bus, bdf, PCI_DEVICE_ID, &device,
PCI_SIZE_16);
/* Find this device in the device tree */
ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
+ debug(": find ret=%d\n", ret);
/* If nothing in the device tree, bind a device */
if (ret == -ENODEV) {
return;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
+ if (hose->region_count == MAX_PCI_REGIONS) {
+ pr_err("maximum number of regions parsed, aborting\n");
+ break;
+ }
+
if (bd->bi_dram[i].size) {
pci_set_region(hose->regions + hose->region_count++,
bd->bi_dram[i].start,
if (ret)
return ret;
-#ifdef CONFIG_PCI_PNP
+#if CONFIG_IS_ENABLED(PCI_PNP)
ret = pci_auto_config_devices(bus);
if (ret < 0)
return ret;
return 0;
}
-static int pci_uclass_child_post_bind(struct udevice *dev)
+int pci_get_devfn(struct udevice *dev)
{
- struct pci_child_platdata *pplat;
struct fdt_pci_addr addr;
int ret;
+ /* Extract the devfn from fdt_pci_addr */
+ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
+ "reg", &addr);
+ if (ret) {
+ if (ret != -ENOENT)
+ return -EINVAL;
+ }
+
+ return addr.phys_hi & 0xff00;
+}
+
+static int pci_uclass_child_post_bind(struct udevice *dev)
+{
+ struct pci_child_platdata *pplat;
+
if (!dev_of_valid(dev))
return 0;
ofnode_read_pci_vendev(dev_ofnode(dev), &pplat->vendor, &pplat->device);
/* Extract the devfn from fdt_pci_addr */
- ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG, "reg",
- &addr);
- if (ret) {
- if (ret != -ENOENT)
- return -EINVAL;
- } else {
- pplat->devfn = addr.phys_hi & 0xff00;
- }
+ pplat->devfn = pci_get_devfn(dev);
return 0;
}
return bus_addr;
}
+static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, int flags,
+ int ea_off)
+{
+ int ea_cnt, i, entry_size;
+ int bar_id = (bar - PCI_BASE_ADDRESS_0) >> 2;
+ u32 ea_entry;
+ phys_addr_t addr;
+
+ /* EA capability structure header */
+ dm_pci_read_config32(dev, ea_off, &ea_entry);
+ ea_cnt = (ea_entry >> 16) & PCI_EA_NUM_ENT_MASK;
+ ea_off += PCI_EA_FIRST_ENT;
+
+ for (i = 0; i < ea_cnt; i++, ea_off += entry_size) {
+ /* Entry header */
+ dm_pci_read_config32(dev, ea_off, &ea_entry);
+ entry_size = ((ea_entry & PCI_EA_ES) + 1) << 2;
+
+ if (((ea_entry & PCI_EA_BEI) >> 4) != bar_id)
+ continue;
+
+ /* Base address, 1st DW */
+ dm_pci_read_config32(dev, ea_off + 4, &ea_entry);
+ addr = ea_entry & PCI_EA_FIELD_MASK;
+ if (ea_entry & PCI_EA_IS_64) {
+ /* Base address, 2nd DW, skip over 4B MaxOffset */
+ dm_pci_read_config32(dev, ea_off + 12, &ea_entry);
+ addr |= ((u64)ea_entry) << 32;
+ }
+
+ /* size ignored for now */
+ return map_physmem(addr, flags, 0);
+ }
+
+ return 0;
+}
+
void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
{
pci_addr_t pci_bus_addr;
u32 bar_response;
+ int ea_off;
+
+ /*
+ * if the function supports Enhanced Allocation use that instead of
+ * BARs
+ */
+ ea_off = dm_pci_find_capability(dev, PCI_CAP_ID_EA);
+ if (ea_off)
+ return dm_pci_map_ea_bar(dev, bar, flags, ea_off);
/* read BAR address */
dm_pci_read_config32(dev, bar, &bar_response);
return dm_pci_find_next_ext_capability(dev, 0, cap);
}
+int dm_pci_flr(struct udevice *dev)
+{
+ int pcie_off;
+ u32 cap;
+
+ /* look for PCI Express Capability */
+ pcie_off = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pcie_off)
+ return -ENOENT;
+
+ /* check FLR capability */
+ dm_pci_read_config32(dev, pcie_off + PCI_EXP_DEVCAP, &cap);
+ if (!(cap & PCI_EXP_DEVCAP_FLR))
+ return -ENOENT;
+
+ dm_pci_clrset_config16(dev, pcie_off + PCI_EXP_DEVCTL, 0,
+ PCI_EXP_DEVCTL_BCR_FLR);
+
+ /* wait 100ms, per PCI spec */
+ mdelay(100);
+
+ return 0;
+}
+
UCLASS_DRIVER(pci) = {
.id = UCLASS_PCI,
.name = "pci",
* Enumerate all known controller devices. Enumeration has the side-
* effect of probing them, so PCIe devices will be enumerated too.
*/
- for (uclass_first_device(UCLASS_PCI, &bus);
+ for (uclass_first_device_check(UCLASS_PCI, &bus);
bus;
- uclass_next_device(&bus)) {
+ uclass_next_device_check(&bus)) {
;
}
}