/* * Copyright (c) 2014 Google, Inc * Written by Simon Glass * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; struct pci_controller *pci_bus_to_hose(int busnum) { struct udevice *bus; int ret; ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus); if (ret) { debug("%s: Cannot get bus %d: ret=%d\n", __func__, busnum, ret); return NULL; } return dev_get_uclass_priv(bus); } /** * pci_get_bus_max() - returns the bus number of the last active bus * * @return last bus number, or -1 if no active buses */ static int pci_get_bus_max(void) { struct udevice *bus; struct uclass *uc; int ret = -1; ret = uclass_get(UCLASS_PCI, &uc); uclass_foreach_dev(bus, uc) { if (bus->seq > ret) ret = bus->seq; } debug("%s: ret=%d\n", __func__, ret); return ret; } int pci_last_busno(void) { struct pci_controller *hose; struct udevice *bus; struct uclass *uc; int ret; debug("pci_last_busno\n"); ret = uclass_get(UCLASS_PCI, &uc); if (ret || list_empty(&uc->dev_head)) return -1; /* Probe the last bus */ bus = list_entry(uc->dev_head.prev, struct udevice, uclass_node); debug("bus = %p, %s\n", bus, bus->name); assert(bus); ret = device_probe(bus); if (ret) return ret; /* If that bus has bridges, we may have new buses now. Get the last */ bus = list_entry(uc->dev_head.prev, struct udevice, uclass_node); hose = dev_get_uclass_priv(bus); debug("bus = %s, hose = %p\n", bus->name, hose); return hose->last_busno; } int pci_get_ff(enum pci_size_t size) { switch (size) { case PCI_SIZE_8: return 0xff; case PCI_SIZE_16: return 0xffff; default: return 0xffffffff; } } int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn, struct udevice **devp) { struct udevice *dev; for (device_find_first_child(bus, &dev); dev; device_find_next_child(&dev)) { struct pci_child_platdata *pplat; pplat = dev_get_parent_platdata(dev); if (pplat && pplat->devfn == find_devfn) { *devp = dev; return 0; } } return -ENODEV; } int pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp) { struct udevice *bus; int ret; ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus); if (ret) return ret; return pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), devp); } static int pci_device_matches_ids(struct udevice *dev, struct pci_device_id *ids) { struct pci_child_platdata *pplat; int i; pplat = dev_get_parent_platdata(dev); if (!pplat) return -EINVAL; for (i = 0; ids[i].vendor != 0; i++) { if (pplat->vendor == ids[i].vendor && pplat->device == ids[i].device) return i; } return -EINVAL; } int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids, int *indexp, struct udevice **devp) { struct udevice *dev; /* Scan all devices on this bus */ for (device_find_first_child(bus, &dev); dev; device_find_next_child(&dev)) { if (pci_device_matches_ids(dev, ids) >= 0) { if ((*indexp)-- <= 0) { *devp = dev; return 0; } } } return -ENODEV; } int pci_find_device_id(struct pci_device_id *ids, int index, struct udevice **devp) { struct udevice *bus; /* Scan all known buses */ for (uclass_first_device(UCLASS_PCI, &bus); bus; uclass_next_device(&bus)) { if (!pci_bus_find_devices(bus, ids, &index, devp)) return 0; } *devp = NULL; return -ENODEV; } int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset, unsigned long value, enum pci_size_t size) { struct dm_pci_ops *ops; ops = pci_get_ops(bus); if (!ops->write_config) return -ENOSYS; return ops->write_config(bus, bdf, offset, value, size); } int pci_write_config(pci_dev_t bdf, int offset, unsigned long value, enum pci_size_t size) { struct udevice *bus; int ret; ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus); if (ret) return ret; return pci_bus_write_config(bus, PCI_MASK_BUS(bdf), offset, value, size); } int pci_write_config32(pci_dev_t bdf, int offset, u32 value) { return pci_write_config(bdf, offset, value, PCI_SIZE_32); } int pci_write_config16(pci_dev_t bdf, int offset, u16 value) { return pci_write_config(bdf, offset, value, PCI_SIZE_16); } int pci_write_config8(pci_dev_t bdf, int offset, u8 value) { return pci_write_config(bdf, offset, value, PCI_SIZE_8); } int pci_bus_read_config(struct udevice *bus, pci_dev_t bdf, int offset, unsigned long *valuep, enum pci_size_t size) { struct dm_pci_ops *ops; ops = pci_get_ops(bus); if (!ops->read_config) return -ENOSYS; return ops->read_config(bus, bdf, offset, valuep, size); } int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep, enum pci_size_t size) { struct udevice *bus; int ret; ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus); if (ret) return ret; return pci_bus_read_config(bus, PCI_MASK_BUS(bdf), offset, valuep, size); } int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep) { unsigned long value; int ret; ret = pci_read_config(bdf, offset, &value, PCI_SIZE_32); if (ret) return ret; *valuep = value; return 0; } int pci_read_config16(pci_dev_t bdf, int offset, u16 *valuep) { unsigned long value; int ret; ret = pci_read_config(bdf, offset, &value, PCI_SIZE_16); if (ret) return ret; *valuep = value; return 0; } int pci_read_config8(pci_dev_t bdf, int offset, u8 *valuep) { unsigned long value; int ret; ret = pci_read_config(bdf, offset, &value, PCI_SIZE_8); if (ret) return ret; *valuep = value; return 0; } int pci_auto_config_devices(struct udevice *bus) { struct pci_controller *hose = bus->uclass_priv; unsigned int sub_bus; struct udevice *dev; int ret; sub_bus = bus->seq; debug("%s: start\n", __func__); pciauto_config_init(hose); for (ret = device_find_first_child(bus, &dev); !ret && dev; ret = device_find_next_child(&dev)) { struct pci_child_platdata *pplat; struct pci_controller *ctlr_hose; pplat = dev_get_parent_platdata(dev); unsigned int max_bus; pci_dev_t bdf; bdf = PCI_ADD_BUS(bus->seq, pplat->devfn); debug("%s: device %s\n", __func__, dev->name); /* The root controller has the region information */ ctlr_hose = hose->ctlr->uclass_priv; max_bus = pciauto_config_device(ctlr_hose, bdf); sub_bus = max(sub_bus, max_bus); } debug("%s: done\n", __func__); return sub_bus; } int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf) { struct udevice *parent, *bus; int sub_bus; int ret; debug("%s\n", __func__); parent = hose->bus; /* Find the bus within the parent */ ret = pci_bus_find_devfn(parent, bdf, &bus); if (ret) { debug("%s: Cannot find device %x on bus %s: %d\n", __func__, bdf, parent->name, ret); return ret; } sub_bus = pci_get_bus_max() + 1; debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name); pciauto_prescan_setup_bridge(hose, bdf, sub_bus); ret = device_probe(bus); if (ret) { debug("%s: Cannot probe bus bus %s: %d\n", __func__, bus->name, ret); return ret; } if (sub_bus != bus->seq) { printf("%s: Internal error, bus '%s' got seq %d, expected %d\n", __func__, bus->name, bus->seq, sub_bus); return -EPIPE; } sub_bus = pci_get_bus_max(); pciauto_postscan_setup_bridge(hose, bdf, sub_bus); return sub_bus; } int pci_bind_bus_devices(struct udevice *bus) { ulong vendor, device; ulong header_type; pci_dev_t devfn, end; bool found_multi; int ret; found_multi = false; end = PCI_DEVFN(PCI_MAX_PCI_DEVICES - 1, PCI_MAX_PCI_FUNCTIONS - 1); for (devfn = PCI_DEVFN(0, 0); devfn < end; devfn += PCI_DEVFN(0, 1)) { struct pci_child_platdata *pplat; struct udevice *dev; ulong class; if (PCI_FUNC(devfn) && !found_multi) continue; /* Check only the first access, we don't expect problems */ ret = pci_bus_read_config(bus, devfn, PCI_HEADER_TYPE, &header_type, PCI_SIZE_8); if (ret) goto error; pci_bus_read_config(bus, devfn, PCI_VENDOR_ID, &vendor, PCI_SIZE_16); if (vendor == 0xffff || vendor == 0x0000) continue; if (!PCI_FUNC(devfn)) found_multi = header_type & 0x80; debug("%s: bus %d/%s: found device %x, function %d\n", __func__, bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn)); pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device, PCI_SIZE_16); pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &class, PCI_SIZE_16); /* Find this device in the device tree */ ret = pci_bus_find_devfn(bus, devfn, &dev); /* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV) { char name[30], *str; const char *drv; sprintf(name, "pci_%x:%x.%x", bus->seq, PCI_DEV(devfn), PCI_FUNC(devfn)); str = strdup(name); if (!str) return -ENOMEM; drv = class == PCI_CLASS_BRIDGE_PCI ? "pci_bridge_drv" : "pci_generic_drv"; ret = device_bind_driver(bus, drv, str, &dev); } if (ret) return ret; /* Update the platform data */ pplat = dev_get_parent_platdata(dev); pplat->devfn = devfn; pplat->vendor = vendor; pplat->device = device; pplat->class = class; } return 0; error: printf("Cannot read bus configuration: %d\n", ret); return ret; } static int pci_uclass_post_bind(struct udevice *bus) { /* * Scan the device tree for devices. This does not probe the PCI bus, * as this is not permitted while binding. It just finds devices * mentioned in the device tree. * * Before relocation, only bind devices marked for pre-relocation * use. */ return dm_scan_fdt_node(bus, gd->fdt_blob, bus->of_offset, gd->flags & GD_FLG_RELOC ? false : true); } static int decode_regions(struct pci_controller *hose, const void *blob, int parent_node, int node) { int pci_addr_cells, addr_cells, size_cells; int cells_per_record; phys_addr_t addr; const u32 *prop; int len; int i; prop = fdt_getprop(blob, node, "ranges", &len); if (!prop) return -EINVAL; pci_addr_cells = fdt_address_cells(blob, node); addr_cells = fdt_address_cells(blob, parent_node); size_cells = fdt_size_cells(blob, node); /* PCI addresses are always 3-cells */ len /= sizeof(u32); cells_per_record = pci_addr_cells + addr_cells + size_cells; hose->region_count = 0; debug("%s: len=%d, cells_per_record=%d\n", __func__, len, cells_per_record); for (i = 0; i < MAX_PCI_REGIONS; i++, len -= cells_per_record) { u64 pci_addr, addr, size; int space_code; u32 flags; int type; if (len < cells_per_record) break; flags = fdt32_to_cpu(prop[0]); space_code = (flags >> 24) & 3; pci_addr = fdtdec_get_number(prop + 1, 2); prop += pci_addr_cells; addr = fdtdec_get_number(prop, addr_cells); prop += addr_cells; size = fdtdec_get_number(prop, size_cells); prop += size_cells; debug("%s: region %d, pci_addr=%" PRIx64 ", addr=%" PRIx64 ", size=%" PRIx64 ", space_code=%d\n", __func__, hose->region_count, pci_addr, addr, size, space_code); if (space_code & 2) { type = flags & (1U << 30) ? PCI_REGION_PREFETCH : PCI_REGION_MEM; } else if (space_code & 1) { type = PCI_REGION_IO; } else { continue; } debug(" - type=%d\n", type); pci_set_region(hose->regions + hose->region_count++, pci_addr, addr, size, type); } /* Add a region for our local memory */ addr = gd->ram_size; if (gd->pci_ram_top && gd->pci_ram_top < addr) addr = gd->pci_ram_top; pci_set_region(hose->regions + hose->region_count++, 0, 0, addr, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); return 0; } static int pci_uclass_pre_probe(struct udevice *bus) { struct pci_controller *hose; int ret; debug("%s, bus=%d/%s, parent=%s\n", __func__, bus->seq, bus->name, bus->parent->name); hose = bus->uclass_priv; /* For bridges, use the top-level PCI controller */ if (device_get_uclass_id(bus->parent) == UCLASS_ROOT) { hose->ctlr = bus; ret = decode_regions(hose, gd->fdt_blob, bus->parent->of_offset, bus->of_offset); if (ret) { debug("%s: Cannot decode regions\n", __func__); return ret; } } else { struct pci_controller *parent_hose; parent_hose = dev_get_uclass_priv(bus->parent); hose->ctlr = parent_hose->bus; } hose->bus = bus; hose->first_busno = bus->seq; hose->last_busno = bus->seq; return 0; } static int pci_uclass_post_probe(struct udevice *bus) { int ret; /* Don't scan buses before relocation */ if (!(gd->flags & GD_FLG_RELOC)) return 0; debug("%s: probing bus %d\n", __func__, bus->seq); ret = pci_bind_bus_devices(bus); if (ret) return ret; #ifdef CONFIG_PCI_PNP ret = pci_auto_config_devices(bus); #endif return ret < 0 ? ret : 0; } static int pci_uclass_child_post_bind(struct udevice *dev) { struct pci_child_platdata *pplat; struct fdt_pci_addr addr; int ret; if (dev->of_offset == -1) return 0; /* * We could read vendor, device, class if available. But for now we * just check the address. */ pplat = dev_get_parent_platdata(dev); ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset, FDT_PCI_SPACE_CONFIG, "reg", &addr); if (ret) { if (ret != -ENOENT) return -EINVAL; } else { /* extract the bdf from fdt_pci_addr */ pplat->devfn = addr.phys_hi & 0xffff00; } return 0; } int pci_bridge_read_config(struct udevice *bus, pci_dev_t devfn, uint offset, ulong *valuep, enum pci_size_t size) { struct pci_controller *hose = bus->uclass_priv; pci_dev_t bdf = PCI_ADD_BUS(bus->seq, devfn); return pci_bus_read_config(hose->ctlr, bdf, offset, valuep, size); } int pci_bridge_write_config(struct udevice *bus, pci_dev_t devfn, uint offset, ulong value, enum pci_size_t size) { struct pci_controller *hose = bus->uclass_priv; pci_dev_t bdf = PCI_ADD_BUS(bus->seq, devfn); return pci_bus_write_config(hose->ctlr, bdf, offset, value, size); } UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", .flags = DM_UC_FLAG_SEQ_ALIAS, .post_bind = pci_uclass_post_bind, .pre_probe = pci_uclass_pre_probe, .post_probe = pci_uclass_post_probe, .child_post_bind = pci_uclass_child_post_bind, .per_device_auto_alloc_size = sizeof(struct pci_controller), .per_child_platdata_auto_alloc_size = sizeof(struct pci_child_platdata), }; static const struct dm_pci_ops pci_bridge_ops = { .read_config = pci_bridge_read_config, .write_config = pci_bridge_write_config, }; static const struct udevice_id pci_bridge_ids[] = { { .compatible = "pci-bridge" }, { } }; U_BOOT_DRIVER(pci_bridge_drv) = { .name = "pci_bridge_drv", .id = UCLASS_PCI, .of_match = pci_bridge_ids, .ops = &pci_bridge_ops, }; UCLASS_DRIVER(pci_generic) = { .id = UCLASS_PCI_GENERIC, .name = "pci_generic", }; static const struct udevice_id pci_generic_ids[] = { { .compatible = "pci-generic" }, { } }; U_BOOT_DRIVER(pci_generic_drv) = { .name = "pci_generic_drv", .id = UCLASS_PCI_GENERIC, .of_match = pci_generic_ids, };