summaryrefslogtreecommitdiff
path: root/sys/arch/socppc/dev/socpcic.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-09-06 20:09:35 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-09-06 20:09:35 +0000
commit2fd91aac38ea3f6322903b6921b4b83d15b292a9 (patch)
treefcff737b4795e5428b2fd74fbc4d830a17f804bd /sys/arch/socppc/dev/socpcic.c
parent530de8f9420591168bf062e320611b45167f642a (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.c158
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", &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 *