From 01259c93904fcffc4d127219145ecb0d44fa5ae1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 3 Aug 2018 01:14:33 -0700 Subject: pci: Remove 440ep-specific macros These macros should not be put in the generic pci.h header file. Since they are not referenced anywhere, remove them completely. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- include/pci.h | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'include/pci.h') diff --git a/include/pci.h b/include/pci.h index 8e27cbfaf1..427094cd70 100644 --- a/include/pci.h +++ b/include/pci.h @@ -271,21 +271,6 @@ #define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ #define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ -/* From 440ep */ -#define PCI_ERREN 0x48 /* Error Enable */ -#define PCI_ERRSTS 0x49 /* Error Status */ -#define PCI_BRDGOPT1 0x4A /* PCI Bridge Options 1 */ -#define PCI_PLBSESR0 0x4C /* PCI PLB Slave Error Syndrome 0 */ -#define PCI_PLBSESR1 0x50 /* PCI PLB Slave Error Syndrome 1 */ -#define PCI_PLBSEAR 0x54 /* PCI PLB Slave Error Address */ -#define PCI_CAPID 0x58 /* Capability Identifier */ -#define PCI_NEXTITEMPTR 0x59 /* Next Item Pointer */ -#define PCI_PMC 0x5A /* Power Management Capabilities */ -#define PCI_PMCSR 0x5C /* Power Management Control Status */ -#define PCI_PMCSRBSE 0x5E /* PMCSR PCI to PCI Bridge Support Extensions */ -#define PCI_BRDGOPT2 0x60 /* PCI Bridge Options 2 */ -#define PCI_PMSCRR 0x64 /* Power Management State Change Request Re. */ - /* Header type 2 (CardBus bridges) */ #define PCI_CB_CAPABILITY_LIST 0x14 /* 0x15 reserved */ -- cgit v1.2.3 From 4345998ae9dfad7ba0beb54ad4322134557504a9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 3 Aug 2018 01:14:45 -0700 Subject: pci: sandbox: Support dynamically binding device driver At present all emulated sandbox pci devices must be present in the device tree in order to be used. The real world pci uclass driver supports pci device driver matching, and we should add such support on sandbox too. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- doc/driver-model/pci-info.txt | 28 ++++++++++++++++ drivers/pci/pci-emul-uclass.c | 14 +++++--- drivers/pci/pci_sandbox.c | 78 +++++++++++++++++++++++++++++++++++++++---- include/pci.h | 3 +- 4 files changed, 112 insertions(+), 11 deletions(-) (limited to 'include/pci.h') diff --git a/doc/driver-model/pci-info.txt b/doc/driver-model/pci-info.txt index 52b4389d2c..e1701d1fbc 100644 --- a/doc/driver-model/pci-info.txt +++ b/doc/driver-model/pci-info.txt @@ -133,3 +133,31 @@ When this bus is scanned we will end up with something like this: When accesses go to the pci@1f,0 device they are forwarded to its child, the emulator. + +The sandbox PCI drivers also support dynamic driver binding, allowing device +driver to declare the driver binding information via U_BOOT_PCI_DEVICE(), +eliminating the need to provide any device tree node under the host controller +node. It is required a "sandbox,dev-info" property must be provided in the +host controller node for this functionality to work. + + pci1: pci-controller1 { + compatible = "sandbox,pci"; + ... + sandbox,dev-info = <0x08 0x00 0x1234 0x5678 + 0x0c 0x00 0x1234 0x5678>; + }; + +The "sandbox,dev-info" property specifies all dynamic PCI devices on this bus. +Each dynamic PCI device is encoded as 4 cells a group. The first and second +cells are PCI device number and function number respectively. The third and +fourth cells are PCI vendor ID and device ID respectively. + +When this bus is scanned we will end up with something like this: + + pci [ + ] pci_sandbo |-- pci-controller1 + pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul + pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul + +Note the difference from the statically declared device nodes is that the +device is directly attached to the host controller, instead of via a container +device like pci@1f,0. diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 8570a5da20..e9d2f49793 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -16,21 +16,27 @@ struct sandbox_pci_priv { }; int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, - struct udevice **emulp) + struct udevice **containerp, struct udevice **emulp) { struct udevice *dev; int ret; + *containerp = NULL; ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(find_devfn), &dev); if (ret) { debug("%s: Could not find emulator for dev %x\n", __func__, find_devfn); return ret; } + *containerp = dev; - ret = device_find_first_child(dev, emulp); - if (ret) - return ret; + if (device_get_uclass_id(dev) == UCLASS_PCI_GENERIC) { + ret = device_find_first_child(dev, emulp); + if (ret) + return ret; + } else { + *emulp = dev; + } return *emulp ? 0 : -ENODEV; } diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c index 67cd733e61..119a98d061 100644 --- a/drivers/pci/pci_sandbox.c +++ b/drivers/pci/pci_sandbox.c @@ -10,15 +10,27 @@ #include #include +#define FDT_DEV_INFO_CELLS 4 +#define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32)) + +#define SANDBOX_PCI_DEVFN(d, f) ((d << 3) | f) + +struct sandbox_pci_priv { + struct { + u16 vendor; + u16 device; + } vendev[256]; +}; + static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn, uint offset, ulong value, enum pci_size_t size) { struct dm_pci_emul_ops *ops; - struct udevice *emul; + struct udevice *container, *emul; int ret; - ret = sandbox_pci_get_emul(bus, devfn, &emul); + ret = sandbox_pci_get_emul(bus, devfn, &container, &emul); if (ret) return ret == -ENODEV ? 0 : ret; ops = pci_get_emul_ops(emul); @@ -33,14 +45,31 @@ static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn, enum pci_size_t size) { struct dm_pci_emul_ops *ops; - struct udevice *emul; + struct udevice *container, *emul; + struct sandbox_pci_priv *priv = dev_get_priv(bus); int ret; /* Prepare the default response */ *valuep = pci_get_ff(size); - ret = sandbox_pci_get_emul(bus, devfn, &emul); - if (ret) - return ret == -ENODEV ? 0 : ret; + ret = sandbox_pci_get_emul(bus, devfn, &container, &emul); + if (ret) { + if (!container) { + u16 vendor, device; + + devfn = SANDBOX_PCI_DEVFN(PCI_DEV(devfn), + PCI_FUNC(devfn)); + vendor = priv->vendev[devfn].vendor; + device = priv->vendev[devfn].device; + if (offset == PCI_VENDOR_ID && vendor) + *valuep = vendor; + else if (offset == PCI_DEVICE_ID && device) + *valuep = device; + + return 0; + } else { + return ret == -ENODEV ? 0 : ret; + } + } ops = pci_get_emul_ops(emul); if (!ops || !ops->read_config) return -ENOSYS; @@ -48,6 +77,41 @@ static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn, return ops->read_config(emul, offset, valuep, size); } +static int sandbox_pci_probe(struct udevice *dev) +{ + struct sandbox_pci_priv *priv = dev_get_priv(dev); + const fdt32_t *cell; + u8 pdev, pfn, devfn; + int len; + + cell = ofnode_get_property(dev_ofnode(dev), "sandbox,dev-info", &len); + if (!cell) + return 0; + + if ((len % FDT_DEV_INFO_SIZE) == 0) { + int num = len / FDT_DEV_INFO_SIZE; + int i; + + for (i = 0; i < num; i++) { + debug("dev info #%d: %02x %02x %04x %04x\n", i, + fdt32_to_cpu(cell[0]), fdt32_to_cpu(cell[1]), + fdt32_to_cpu(cell[2]), fdt32_to_cpu(cell[3])); + + pdev = fdt32_to_cpu(cell[0]); + pfn = fdt32_to_cpu(cell[1]); + if (pdev > 31 || pfn > 7) + continue; + devfn = SANDBOX_PCI_DEVFN(pdev, pfn); + priv->vendev[devfn].vendor = fdt32_to_cpu(cell[2]); + priv->vendev[devfn].device = fdt32_to_cpu(cell[3]); + + cell += FDT_DEV_INFO_CELLS; + } + } + + return 0; +} + static const struct dm_pci_ops sandbox_pci_ops = { .read_config = sandbox_pci_read_config, .write_config = sandbox_pci_write_config, @@ -63,6 +127,8 @@ U_BOOT_DRIVER(pci_sandbox) = { .id = UCLASS_PCI, .of_match = sandbox_pci_ids, .ops = &sandbox_pci_ops, + .probe = sandbox_pci_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv), /* Attach an emulator if we can */ .child_post_bind = dm_scan_fdt_dev, diff --git a/include/pci.h b/include/pci.h index 427094cd70..c0ae5d1673 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1441,11 +1441,12 @@ struct dm_pci_emul_ops { * * @bus: PCI bus to search * @find_devfn: PCI device and function address (PCI_DEVFN()) + * @containerp: Returns container device if found * @emulp: Returns emulated device if found * @return 0 if found, -ENODEV if not found */ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, - struct udevice **emulp); + struct udevice **containerp, struct udevice **emulp); #endif /* CONFIG_DM_PCI */ -- cgit v1.2.3 From 5d544f962f7b970c118eaa13f1b874572ab5c28f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 3 Aug 2018 01:14:51 -0700 Subject: pci: Add all known capability and extended capability ids Currently we don't have a complete list of capability and extended capability ids. This adds them. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- include/pci.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'include/pci.h') diff --git a/include/pci.h b/include/pci.h index c0ae5d1673..83a40a5adf 100644 --- a/include/pci.h +++ b/include/pci.h @@ -318,7 +318,21 @@ #define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor-Specific */ +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */ +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ +#define PCI_CAP_ID_EA 0x14 /* PCI Enhanced Allocation */ +#define PCI_CAP_ID_MAX PCI_CAP_ID_EA #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ #define PCI_CAP_SIZEOF 4 @@ -434,6 +448,10 @@ #define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe Capability */ #define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ #define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ +#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ +#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */ +#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM /* Include the ID list */ -- cgit v1.2.3 From dac01fd89d41d98cd4ce040a0d10eb67c523f63a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 3 Aug 2018 01:14:52 -0700 Subject: dm: pci: Add APIs to find capability and extended capability This introduces two new APIs dm_pci_find_capability() and dm_pci_find_ext_capability() to get PCI capability address and PCI express extended capability address for a given PCI device. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/pci/pci-uclass.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ include/pci.h | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) (limited to 'include/pci.h') diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 5eb68415cd..e9671d9b76 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1320,6 +1320,74 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags) return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE); } +int dm_pci_find_capability(struct udevice *dev, int cap) +{ + u16 status; + u8 header_type; + int ttl = PCI_FIND_CAP_TTL; + u8 id; + u16 ent; + u8 pos; + + dm_pci_read_config16(dev, PCI_STATUS, &status); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type); + if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS) + pos = PCI_CB_CAPABILITY_LIST; + else + pos = PCI_CAPABILITY_LIST; + + dm_pci_read_config8(dev, pos, &pos); + while (ttl--) { + if (pos < PCI_STD_HEADER_SIZEOF) + break; + pos &= ~3; + dm_pci_read_config16(dev, pos, &ent); + + id = ent & 0xff; + if (id == 0xff) + break; + if (id == cap) + return pos; + pos = (ent >> 8); + } + + return 0; +} + +int dm_pci_find_ext_capability(struct udevice *dev, int cap) +{ + u32 header; + int ttl; + int pos = PCI_CFG_SPACE_SIZE; + + /* minimum 8 bytes per capability */ + ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; + + dm_pci_read_config32(dev, pos, &header); + /* + * If we have no capabilities, this is indicated by cap ID, + * cap version and next pointer all being 0. + */ + if (header == 0) + return 0; + + while (ttl--) { + if (PCI_EXT_CAP_ID(header) == cap) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (pos < PCI_CFG_SPACE_SIZE) + break; + + dm_pci_read_config32(dev, pos, &header); + } + + return 0; +} + UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", diff --git a/include/pci.h b/include/pci.h index 83a40a5adf..938a8390cb 100644 --- a/include/pci.h +++ b/include/pci.h @@ -17,6 +17,7 @@ * Under PCI, each device has 256 bytes of configuration address space, * of which the first 64 bytes are standardized as follows: */ +#define PCI_STD_HEADER_SIZEOF 64 #define PCI_VENDOR_ID 0x00 /* 16 bits */ #define PCI_DEVICE_ID 0x02 /* 16 bits */ #define PCI_COMMAND 0x04 /* 16 bits */ @@ -1311,6 +1312,51 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr, */ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags); +/** + * dm_pci_find_capability() - find a capability + * + * Tell if a device supports a given PCI capability. Returns the + * address of the requested capability structure within the device's + * PCI configuration space or 0 in case the device does not support it. + * + * Possible values for @cap: + * + * %PCI_CAP_ID_MSI Message Signalled Interrupts + * %PCI_CAP_ID_PCIX PCI-X + * %PCI_CAP_ID_EXP PCI Express + * %PCI_CAP_ID_MSIX MSI-X + * + * See PCI_CAP_ID_xxx for the complete capability ID codes. + * + * @dev: PCI device to query + * @cap: capability code + * @return: capability address or 0 if not supported + */ +int dm_pci_find_capability(struct udevice *dev, int cap); + +/** + * dm_pci_find_ext_capability() - find an extended capability + * + * Tell if a device supports a given PCI express extended capability. + * Returns the address of the requested extended capability structure + * within the device's PCI configuration space or 0 in case the device + * does not support it. + * + * Possible values for @cap: + * + * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting + * %PCI_EXT_CAP_ID_VC Virtual Channel + * %PCI_EXT_CAP_ID_DSN Device Serial Number + * %PCI_EXT_CAP_ID_PWR Power Budgeting + * + * See PCI_EXT_CAP_ID_xxx for the complete extended capability ID codes. + * + * @dev: PCI device to query + * @cap: extended capability code + * @return: extended capability address or 0 if not supported + */ +int dm_pci_find_ext_capability(struct udevice *dev, int cap); + #define dm_pci_virt_to_bus(dev, addr, flags) \ dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags)) #define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \ -- cgit v1.2.3