diff options
-rw-r--r-- | src/device/Makefile.inc | 3 | ||||
-rw-r--r-- | src/device/pci_early.c | 68 | ||||
-rw-r--r-- | src/include/device/pci.h | 6 |
3 files changed, 74 insertions, 3 deletions
diff --git a/src/device/Makefile.inc b/src/device/Makefile.inc index 1dbb510024..ce412b7840 100644 --- a/src/device/Makefile.inc +++ b/src/device/Makefile.inc @@ -13,7 +13,8 @@ ramstage-$(CONFIG_ARCH_X86) += pnp_device.c ramstage-$(CONFIG_PCI) += pci_ops.c ramstage-y += smbus_ops.c -romstage-y+= device_romstage.c +romstage-y += device_romstage.c +romstage-$(CONFIG_PCI) += pci_early.c subdirs-y += oprom diff --git a/src/device/pci_early.c b/src/device/pci_early.c new file mode 100644 index 0000000000..c15a4d0f77 --- /dev/null +++ b/src/device/pci_early.c @@ -0,0 +1,68 @@ +/* + * This file is part of the coreboot project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include <arch/io.h> +#include <device/pci.h> +#include <device/pci_def.h> + +unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) +{ + unsigned pos = 0; + u16 status; + unsigned reps = 48; + + status = pci_read_config16(dev, PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + u8 hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE); + switch (hdr_type & 0x7f) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + pos = PCI_CAPABILITY_LIST; + break; + case PCI_HEADER_TYPE_CARDBUS: + pos = PCI_CB_CAPABILITY_LIST; + break; + default: + return 0; + } + + pos = pci_read_config8(dev, pos); + while (reps-- && (pos >= 0x40)) { /* Loop through the linked list. */ + int this_cap; + + pos &= ~3; + this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID); + if (this_cap == 0xff) + break; + + if (!last && (this_cap == cap)) + return pos; + + if (last == pos) + last = 0; + + pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT); + } + return 0; +} + +unsigned pci_find_capability(device_t dev, unsigned cap) +{ + return pci_find_next_capability(dev, cap, 0); +} diff --git a/src/include/device/pci.h b/src/include/device/pci.h index 7504cc7269..29d988fd9e 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -20,6 +20,7 @@ #include <stdint.h> #include <stddef.h> #include <arch/rules.h> +#include <arch/io.h> #include <device/pci_def.h> #include <device/resource.h> #include <device/device.h> @@ -76,8 +77,6 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf uint8_t pci_moving_config8(struct device *dev, unsigned reg); uint16_t pci_moving_config16(struct device *dev, unsigned reg); uint32_t pci_moving_config32(struct device *dev, unsigned reg); -unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last); -unsigned pci_find_capability(device_t dev, unsigned cap); struct resource *pci_get_resource(struct device *dev, unsigned long index); void pci_dev_set_subsystem(device_t dev, unsigned vendor, unsigned device); void pci_dev_init(struct device *dev); @@ -101,6 +100,9 @@ static inline const struct pci_operations *ops_pci(device_t dev) #endif /* ! __SIMPLE_DEVICE__ */ +unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last); +unsigned pci_find_capability(device_t dev, unsigned cap); + #endif /* CONFIG_PCI */ #endif /* PCI_H */ |