diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-09-06 20:09:35 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-09-06 20:09:35 +0000 |
commit | 2fd91aac38ea3f6322903b6921b4b83d15b292a9 (patch) | |
tree | fcff737b4795e5428b2fd74fbc4d830a17f804bd /sys/arch/socppc/dev/socpcic.c | |
parent | 530de8f9420591168bf062e320611b45167f642a (diff) |
Attach devices to obio(4) based on information from the flattened device
tree. Since that information is also used for the PCI interrupts, devices
in mini-PCI slots should work now as well, at least in the rb600.
Diffstat (limited to 'sys/arch/socppc/dev/socpcic.c')
-rw-r--r-- | sys/arch/socppc/dev/socpcic.c | 158 |
1 files changed, 140 insertions, 18 deletions
diff --git a/sys/arch/socppc/dev/socpcic.c b/sys/arch/socppc/dev/socpcic.c index 6207b6143c6..00f6507d2e0 100644 --- a/sys/arch/socppc/dev/socpcic.c +++ b/sys/arch/socppc/dev/socpcic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: socpcic.c,v 1.6 2009/08/26 20:53:51 kettenis Exp $ */ +/* $OpenBSD: socpcic.c,v 1.7 2009/09/06 20:09:34 kettenis Exp $ */ /* * Copyright (c) 2008 Mark Kettenis @@ -23,30 +23,50 @@ #include <machine/autoconf.h> #include <machine/bus.h> +#include <dev/ofw/openfirm.h> + #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> struct socpcic_softc { struct device sc_dev; + + int sc_node; + bus_space_tag_t sc_iot; bus_space_handle_t sc_cfg_ioh; struct ppc_bus_space sc_mem_bus_space; struct ppc_bus_space sc_io_bus_space; + bus_dma_tag_t sc_dmat; struct ppc_pci_chipset sc_pc; + + /* Interrupt mapping. */ + int sc_map_mask[4]; + int *sc_map; + int sc_map_len; }; -int socpcic_match(struct device *, void *, void *); -void socpcic_attach(struct device *, struct device *, void *); +int socpcic_mainbus_match(struct device *, void *, void *); +void socpcic_mainbus_attach(struct device *, struct device *, void *); +int socpcic_obio_match(struct device *, void *, void *); +void socpcic_obio_attach(struct device *, struct device *, void *); -struct cfattach socpcic_ca = { - sizeof(struct socpcic_softc), socpcic_match, socpcic_attach +struct cfattach socpcic_mainbus_ca = { + sizeof(struct socpcic_softc), + socpcic_mainbus_match, socpcic_mainbus_attach +}; + +struct cfattach socpcic_obio_ca = { + sizeof(struct socpcic_softc), + socpcic_obio_match, socpcic_obio_attach }; struct cfdriver socpcic_cd = { NULL, "socpcic", DV_DULL }; +void socpcic_attach(struct socpcic_softc *sc); void socpcic_attach_hook(struct device *, struct device *, struct pcibus_attach_args *); int socpcic_bus_maxdevs(void *, int); @@ -65,19 +85,70 @@ int socpcic_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *); int socpcic_print(void *, const char *); int -socpcic_match(struct device *parent, void *cfdata, void *aux) +socpcic_mainbus_match(struct device *parent, void *cfdata, void *aux) { + struct mainbus_attach_args *ma = aux; + char buf[32]; + + if (OF_getprop(ma->ma_node, "device_type", buf, sizeof(buf)) <= 0 || + strcmp(buf, "pci") != 0) + return (0); + + if (OF_getprop(ma->ma_node, "compatible", buf, sizeof(buf)) <= 0 || + strcmp(buf, "fsl,mpc8349-pci") != 0) + return (0); + return (1); } void -socpcic_attach(struct device *parent, struct device *self, void *aux) +socpcic_mainbus_attach(struct device *parent, struct device *self, void *aux) +{ + struct socpcic_softc *sc = (void *)self; + struct mainbus_attach_args *ma = aux; + int reg[4]; + + if (OF_getprop(ma->ma_node, "reg", ®, sizeof(reg)) < sizeof(reg)) { + printf(": missing registers\n"); + return; + } + + sc->sc_iot = ma->ma_iot; + if (bus_space_map(sc->sc_iot, reg[2], 16, 0, &sc->sc_cfg_ioh)) { + printf(": can't map configuration registers\n"); + return; + } + + sc->sc_node = ma->ma_node; + sc->sc_dmat = ma->ma_dmat; + socpcic_attach(sc); +} + +int +socpcic_obio_match(struct device *parent, void *cfdata, void *aux) +{ + struct obio_attach_args *oa = aux; + char buf[32]; + + if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 || + strcmp(buf, "pci") != 0) + return (0); + + if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 || + strcmp(buf, "83xx") != 0) + return (0); + + return (1); +} + +void +socpcic_obio_attach(struct device *parent, struct device *self, void *aux) { struct socpcic_softc *sc = (void *)self; struct obio_attach_args *oa = aux; - struct pcibus_attach_args pba; - struct extent *io_ex; - struct extent *mem_ex; + + if (oa->oa_offset == 0x8500) + oa->oa_offset = 0x8300; sc->sc_iot = oa->oa_iot; if (bus_space_map(sc->sc_iot, oa->oa_offset, 16, 0, &sc->sc_cfg_ioh)) { @@ -85,6 +156,36 @@ socpcic_attach(struct device *parent, struct device *self, void *aux) return; } + sc->sc_node = oa->oa_node; + sc->sc_dmat = oa->oa_dmat; + socpcic_attach(sc); +} + +void +socpcic_attach(struct socpcic_softc *sc) +{ + struct pcibus_attach_args pba; + struct extent *io_ex; + struct extent *mem_ex; + int len; + + if (OF_getprop(sc->sc_node, "interrupt-map-mask", sc->sc_map_mask, + sizeof(sc->sc_map_mask)) != sizeof(sc->sc_map_mask)) { + printf(": missing interrupt-map-mask\n"); + return; + } + + sc->sc_map_len = OF_getproplen(sc->sc_node, "interrupt-map"); + if (sc->sc_map_len > 0) { + sc->sc_map = malloc(sc->sc_map_len, M_DEVBUF, M_NOWAIT); + if (sc->sc_map == NULL) + panic("out of memory"); + + len = OF_getprop(sc->sc_node, "interrupt-map", + sc->sc_map, sc->sc_map_len); + KASSERT(len == sc->sc_map_len); + } + sc->sc_mem_bus_space.bus_base = 0x80000000; sc->sc_mem_bus_space.bus_size = 0x21000000; sc->sc_mem_bus_space.bus_io = 0; @@ -121,7 +222,7 @@ socpcic_attach(struct device *parent, struct device *self, void *aux) pba.pba_busname = "pci"; pba.pba_iot = &sc->sc_io_bus_space; pba.pba_memt = &sc->sc_mem_bus_space; - pba.pba_dmat = oa->oa_dmat; + pba.pba_dmat = sc->sc_dmat; pba.pba_ioex = io_ex; pba.pba_memex = mem_ex; pba.pba_pc = &sc->sc_pc; @@ -130,7 +231,7 @@ socpcic_attach(struct device *parent, struct device *self, void *aux) printf("\n"); - config_found(self, &pba, socpcic_print); + config_found((struct device *)sc, &pba, socpcic_print); } void @@ -214,12 +315,33 @@ int socpcic_intr_map(void *cpv, pcitag_t tag, int pin, int line, pci_intr_handle_t *ihp) { -#ifdef RB600 - *ihp = 21; /* XXX */ -#else - *ihp = 20; /* XXX */ -#endif - return (0); + struct socpcic_softc *sc = cpv; + int bus, dev, func; + int reg[4]; + int *map; + int len; + + pci_decompose_tag(&sc->sc_pc, tag, &bus, &dev, &func); + + reg[0] = (dev << 11) | (func << 8); + reg[1] = reg[2] = 0; + reg[3] = pin; + + map = sc->sc_map; + len = sc->sc_map_len; + while (len >= 7 * sizeof(int)) { + if ((reg[0] & sc->sc_map_mask[0]) == map[0] && + (reg[1] & sc->sc_map_mask[1]) == map[1] && + (reg[2] & sc->sc_map_mask[2]) == map[2] && + (reg[3] & sc->sc_map_mask[3]) == map[3]) { + *ihp = map[5]; + return (0); + } + len -= 7 * sizeof(int); + map += 7; + } + + return (1); } const char * |