From 637e4588be246477c717869775d81372e2e08ba6 Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Fri, 2 Mar 2007 18:17:02 +0000 Subject: [PATCH] add pci ops so that we can do something. Signed-off-by: Ronald G. Minnich Acked-by: Ronald G. Minnich Acked-by: Stefan Reinauer git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@172 f3766cd6-281f-0410-b1cd-43a5c92072e9 --- arch/x86/Makefile | 1 + arch/x86/pci_ops_auto.c | 92 ++++++++++++++++++++++ arch/x86/pci_ops_conf1.c | 69 ++++++++++++++++ arch/x86/pci_ops_conf2.c | 79 +++++++++++++++++++ arch/x86/pci_ops_mmconf.c | 61 ++++++++++++++ device/pci_ops.c | 4 +- include/cpu/generic/x86/arch/pci_ops.h | 8 +- include/cpu/generic/x86/arch/pciconf.h | 5 +- include/device/pci_ops.h | 1 + mainboard/emulation/qemu-x86/dts | 1 + northbridge/intel/i440bxemulation/i440bx.c | 2 + util/dtc/flattree.c | 15 ++++ 12 files changed, 332 insertions(+), 6 deletions(-) create mode 100644 arch/x86/pci_ops_auto.c create mode 100644 arch/x86/pci_ops_conf1.c create mode 100644 arch/x86/pci_ops_conf2.c create mode 100644 arch/x86/pci_ops_mmconf.c diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 87c03f4c41..3040bdb7f5 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -110,6 +110,7 @@ $(obj)/stage0.init: $(STAGE0_OBJ) STAGE2_LIB_OBJ = $(obj)/stage2.o $(obj)/clog2.o $(obj)/mem.o $(obj)/malloc.o \ $(obj)/tables.o $(obj)/delay.o STAGE2_ARCH_X86_OBJ = $(obj)/archtables.o $(obj)/linuxbios_table.o $(obj)/udelay_io.o +STAGE2_ARCH_X86_OBJ += $(obj)/pci_ops_auto.o $(obj)/pci_ops_conf1.o $(obj)/pci_ops_conf2.o STAGE2_MAINBOARD_OBJ = $(obj)/mainboard.o STAGE2_DYNAMIC_OBJ = $(obj)/statictree.o diff --git a/arch/x86/pci_ops_auto.c b/arch/x86/pci_ops_auto.c new file mode 100644 index 0000000000..913ec764f9 --- /dev/null +++ b/arch/x86/pci_ops_auto.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Before we decide to use direct hardware access mechanisms, we try to do some + * trivial checks to ensure it at least _seems_ to be working -- we just test + * whether bus 00 contains a host bridge (this is similar to checking + * techniques used in XFree86, but ours should be more reliable since we + * attempt to make use of direct access hints provided by the PCI BIOS). + * + * This should be close to trivial, but it isn't, because there are buggy + * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. + */ +static int pci_sanity_check(const struct pci_bus_operations *o) +{ + u16 class, vendor; + unsigned bus; + int devfn; + struct bus pbus; /* Dummy device */ +#define PCI_CLASS_BRIDGE_HOST 0x0600 +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_VENDOR_ID_MOTOROLA 0x1057 + + for (bus = 0, devfn = 0; devfn < 0x100; devfn++) { + class = o->read16(&pbus, bus, devfn, PCI_CLASS_DEVICE); + vendor = o->read16(&pbus, bus, devfn, PCI_VENDOR_ID); + if (((class == PCI_CLASS_BRIDGE_HOST) || (class == PCI_CLASS_DISPLAY_VGA)) || + ((vendor == PCI_VENDOR_ID_INTEL) || (vendor == PCI_VENDOR_ID_COMPAQ) || + (vendor == PCI_VENDOR_ID_MOTOROLA))) { + return 1; + } + } + printk(BIOS_ERR, "PCI: Sanity check failed\n"); + return 0; +} + +const struct pci_bus_operations *pci_check_direct(void) +{ + unsigned int tmp; + + /* + * Check if configuration type 1 works. + */ + { + outb(0x01, 0xCFB); + tmp = inl(0xCF8); + outl(0x80000000, 0xCF8); + if ((inl(0xCF8) == 0x80000000) && + pci_sanity_check(&pci_cf8_conf1)) + { + outl(tmp, 0xCF8); + printk(BIOS_DEBUG, "PCI: Using configuration type 1\n"); + return &pci_cf8_conf1; + } + outl(tmp, 0xCF8); + } + + /* + * Check if configuration type 2 works. + */ + { + outb(0x00, 0xCFB); + outb(0x00, 0xCF8); + outb(0x00, 0xCFA); + if ((inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00) && + pci_sanity_check(&pci_cf8_conf2)) + { + printk(BIOS_DEBUG, "PCI: Using configuration type 2\n"); + return &pci_cf8_conf2; + } + } + + die("pci_check_direct failed\n"); + return NULL; +} + +/** Set the method to be used for PCI, type I or type II + */ +void pci_set_method(struct device * dev) +{ + printk(BIOS_INFO, "Finding PCI configuration type.\n"); + dev->ops->ops_pci_bus = pci_check_direct(); + post_code(0x5f); +} diff --git a/arch/x86/pci_ops_conf1.c b/arch/x86/pci_ops_conf1.c new file mode 100644 index 0000000000..27dd74b84e --- /dev/null +++ b/arch/x86/pci_ops_conf1.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ + +/* this shit really should come with comments ...this is annoying. +#if PCI_IO_CFG_EXT == 0 +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3)) +#else +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | ((where & 0xff) & ~3) | ((where & 0xf00)<<16) ) +#endif +*/ +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3)) + +static u8 pci_conf1_read_config8(struct bus *pbus, int bus, int devfn, int where) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + return inb(0xCFC + (where & 3)); +} + +static u16 pci_conf1_read_config16(struct bus *pbus, int bus, int devfn, int where) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + return inw(0xCFC + (where & 2)); +} + +static u32 pci_conf1_read_config32(struct bus *pbus, int bus, int devfn, int where) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + return inl(0xCFC); +} + +static void pci_conf1_write_config8(struct bus *pbus, int bus, int devfn, int where, u8 value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outb(value, 0xCFC + (where & 3)); +} + +static void pci_conf1_write_config16(struct bus *pbus, int bus, int devfn, int where, u16 value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outw(value, 0xCFC + (where & 2)); +} + +static void pci_conf1_write_config32(struct bus *pbus, int bus, int devfn, int where, u32 value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outl(value, 0xCFC); +} + +#undef CONFIG_CMD + +struct pci_bus_operations pci_cf8_conf1 = +{ + .read8 = pci_conf1_read_config8, + .read16 = pci_conf1_read_config16, + .read32 = pci_conf1_read_config32, + .write8 = pci_conf1_write_config8, + .write16 = pci_conf1_write_config16, + .write32 = pci_conf1_write_config32, +}; diff --git a/arch/x86/pci_ops_conf2.c b/arch/x86/pci_ops_conf2.c new file mode 100644 index 0000000000..d17c2aa752 --- /dev/null +++ b/arch/x86/pci_ops_conf2.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Functions for accessing PCI configuration space with type 2 accesses + */ + +#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) +#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) +#define SET(bus,devfn) outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA); + +static u8 pci_conf2_read_config8(struct bus *pbus, int bus, int devfn, int where) +{ + u8 value; + SET(bus, devfn); + value = inb(IOADDR(devfn, where)); + outb(0, 0xCF8); + return value; +} + +static u16 pci_conf2_read_config16(struct bus *pbus, int bus, int devfn, int where) +{ + u16 value; + SET(bus, devfn); + value = inw(IOADDR(devfn, where)); + outb(0, 0xCF8); + return value; +} + +static u32 pci_conf2_read_config32(struct bus *pbus, int bus, int devfn, int where) +{ + u32 value; + SET(bus, devfn); + value = inl(IOADDR(devfn, where)); + outb(0, 0xCF8); + return value; +} + +static void pci_conf2_write_config8(struct bus *pbus, int bus, int devfn, int where, u8 value) +{ + SET(bus, devfn); + outb(value, IOADDR(devfn, where)); + outb(0, 0xCF8); +} + +static void pci_conf2_write_config16(struct bus *pbus, int bus, int devfn, int where, u16 value) +{ + SET(bus, devfn); + outw(value, IOADDR(devfn, where)); + outb(0, 0xCF8); +} + +static void pci_conf2_write_config32(struct bus *pbus, int bus, int devfn, int where, u32 value) +{ + SET(bus, devfn); + outl(value, IOADDR(devfn, where)); + outb(0, 0xCF8); +} + +#undef SET +#undef IOADDR +#undef FUNC + +struct pci_bus_operations pci_cf8_conf2 = +{ + .read8 = pci_conf2_read_config8, + .read16 = pci_conf2_read_config16, + .read32 = pci_conf2_read_config32, + .write8 = pci_conf2_write_config8, + .write16 = pci_conf2_write_config16, + .write32 = pci_conf2_write_config32, +}; + diff --git a/arch/x86/pci_ops_mmconf.c b/arch/x86/pci_ops_mmconf.c new file mode 100644 index 0000000000..dcff736e39 --- /dev/null +++ b/arch/x86/pci_ops_mmconf.c @@ -0,0 +1,61 @@ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Functions for accessing PCI configuration space with mmconf accesses + */ + +#define PCI_MMIO_ADDR(SEGBUS, DEVFN, WHERE) ( \ + (((SEGBUS) & 0xFFF) << 20) | \ + (((DEVFN) & 0xFF) << 12) | \ + ((WHERE) & 0xFFF)) + +#include + +static uint8_t pci_mmconf_read_config8(struct bus *pbus, int bus, int devfn, int where) +{ + return (read8x(PCI_MMIO_ADDR(bus, devfn, where))); +} + +static uint16_t pci_mmconf_read_config16(struct bus *pbus, int bus, int devfn, int where) +{ + return (read16x(PCI_MMIO_ADDR(bus, devfn, where))); +} + +static uint32_t pci_mmconf_read_config32(struct bus *pbus, int bus, int devfn, int where) +{ + return (read32x(PCI_MMIO_ADDR(bus, devfn, where))); +} + +static void pci_mmconf_write_config8(struct bus *pbus, int bus, int devfn, int where, uint8_t value) +{ + write8x(PCI_MMIO_ADDR(bus, devfn, where), value); +} + +static void pci_mmconf_write_config16(struct bus *pbus, int bus, int devfn, int where, uint16_t value) +{ + write8x(PCI_MMIO_ADDR(bus, devfn, where), value); +} + +static void pci_mmconf_write_config32(struct bus *pbus, int bus, int devfn, int where, uint32_t value) +{ + write8x(PCI_MMIO_ADDR(bus, devfn, where), value); +} + + +const struct pci_bus_operations pci_ops_mmconf = +{ + .read8 = pci_mmconf_read_config8, + .read16 = pci_mmconf_read_config16, + .read32 = pci_mmconf_read_config32, + .write8 = pci_mmconf_write_config8, + .write16 = pci_mmconf_write_config16, + .write32 = pci_mmconf_write_config32, +}; diff --git a/device/pci_ops.c b/device/pci_ops.c index 0dbcc713f8..0162433674 100644 --- a/device/pci_ops.c +++ b/device/pci_ops.c @@ -22,6 +22,8 @@ #include #include +/* walk up the tree from the current dev, in an attempt to find a bus that has ops_pci_bus set */ +/* the assumption here being that if it has ops_pci_bus set, then it can do bus operations */ static struct bus *get_pbus(struct device * dev) { struct bus *pbus = dev->bus; @@ -29,7 +31,7 @@ static struct bus *get_pbus(struct device * dev) pbus = pbus->dev->bus; } if (!pbus || !pbus->dev || !pbus->dev->ops || !pbus->dev->ops->ops_pci_bus) { - printk(BIOS_ALERT,"%s Cannot find pci bus operations", dev_path(dev)); + printk(BIOS_ALERT,"%s: %s(%s) Cannot find pci bus operations", __func__, dev->dtsname, dev_path(dev)); die(""); for(;;); } diff --git a/include/cpu/generic/x86/arch/pci_ops.h b/include/cpu/generic/x86/arch/pci_ops.h index c23858daf6..72f90aa2a9 100644 --- a/include/cpu/generic/x86/arch/pci_ops.h +++ b/include/cpu/generic/x86/arch/pci_ops.h @@ -17,11 +17,11 @@ #ifndef ARCH_I386_PCI_OPS_H #define ARCH_I386_PCI_OPS_H -const struct pci_bus_operations pci_cf8_conf1; -const struct pci_bus_operations pci_cf8_conf2; +extern struct pci_bus_operations pci_cf8_conf1; +extern struct pci_bus_operations pci_cf8_conf2; -#if MMCONF_SUPPORT==1 -const struct pci_bus_operations pci_ops_mmconf; +#if defined(CONFIG_MMCONF_SUPPORT) && (CONFIG_MMCONF_SUPPORT=='y') +extern struct pci_bus_operations pci_ops_mmconf; #endif void pci_set_method(struct device * dev); diff --git a/include/cpu/generic/x86/arch/pciconf.h b/include/cpu/generic/x86/arch/pciconf.h index 5887522c8b..9971552222 100644 --- a/include/cpu/generic/x86/arch/pciconf.h +++ b/include/cpu/generic/x86/arch/pciconf.h @@ -5,10 +5,13 @@ #define PCI_CONF_REG_INDEX 0xcf8 #define PCI_CONF_REG_DATA 0xcfc +/* WTF for now */ +#if 0 #if PCI_IO_CFG_EXT == 0 #define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where)) #else #define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where & 0xff) | ((where & 0xf00)<<16) ) #endif - +#endif +#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where)) #endif diff --git a/include/device/pci_ops.h b/include/device/pci_ops.h index 2c1bfcc0ab..562b80c3fc 100644 --- a/include/device/pci_ops.h +++ b/include/device/pci_ops.h @@ -19,6 +19,7 @@ #include #include +#include u8 pci_read_config8(struct device * dev, unsigned where); u16 pci_read_config16(struct device * dev, unsigned where); diff --git a/mainboard/emulation/qemu-x86/dts b/mainboard/emulation/qemu-x86/dts index 1dbcfa8b39..2f69b3e515 100644 --- a/mainboard/emulation/qemu-x86/dts +++ b/mainboard/emulation/qemu-x86/dts @@ -8,6 +8,7 @@ northbridge,intel,i440bxemulation{ enabled; config="northbridge,intel,i440bxemulation"; + ops="default_pci_ops_dev"; pcipath = "0,0"; /* southbridge,intel,piix4{ pcipath = "0,0"; diff --git a/northbridge/intel/i440bxemulation/i440bx.c b/northbridge/intel/i440bxemulation/i440bx.c index 2253163db6..910f1c2fa2 100644 --- a/northbridge/intel/i440bxemulation/i440bx.c +++ b/northbridge/intel/i440bxemulation/i440bx.c @@ -108,4 +108,6 @@ struct device_operations i440bxemulation_pcidomainops = { .phase5_enable_resources = enable_childrens_resources, .phase6_init = 0, .phase3_scan = pci_domain_scan_bus, + .ops_pci_bus = &pci_cf8_conf1, + }; diff --git a/util/dtc/flattree.c b/util/dtc/flattree.c index 14a8f1bce4..b24d893a8c 100644 --- a/util/dtc/flattree.c +++ b/util/dtc/flattree.c @@ -531,11 +531,26 @@ static void linuxbios_emit_special(FILE *e, struct node *tree) fprintf(f, "\t.chip_ops = &%s_ops,\n", clean(prop->val.val, 0)); fprintf(f, "\t.chip_info = &%s,\n", clean(tree->label, 1)); } + if (streq(prop->name, "ops")){ fprintf(f, "\t.ops = &%s,\n", clean(prop->val.val, 0)); ops_set = 1; } + if (streq(prop->name, "ops_pci")){ + fprintf(f, "\t.ops_pci = &%s,\n", clean(prop->val.val, 0)); + ops_set = 1; + } + + if (streq(prop->name, "ops_pci_bus")){ + fprintf(f, "\t.ops_pci_bus = &%s,\n", clean(prop->val.val, 0)); + ops_set = 1; + } + + if (streq(prop->name, "ops_smbus_bus")){ + fprintf(f, "\t.ops_smbus_bus = &%s,\n", clean(prop->val.val, 0)); + ops_set = 1; + } } if (tree->next_sibling) fprintf(f, "\t.sibling = &dev_%s,\n", tree->next_sibling->label);