diff options
Diffstat (limited to 'sys/powerpc/powermac/hrowpic.c')
-rw-r--r-- | sys/powerpc/powermac/hrowpic.c | 436 |
1 files changed, 108 insertions, 328 deletions
diff --git a/sys/powerpc/powermac/hrowpic.c b/sys/powerpc/powermac/hrowpic.c index d6e5e25..cf8a462 100644 --- a/sys/powerpc/powermac/hrowpic.c +++ b/sys/powerpc/powermac/hrowpic.c @@ -28,15 +28,9 @@ */ /* - * A driver for the PIC found in the Heathrow/Paddington MacIO chips. + * A driver for the PIC found in the Heathrow/Paddington MacIO chips. * This was superseded by an OpenPIC in the Keylargo and beyond * MacIO versions. - * - * The device is initially located in the Open Firmware device tree - * in the earliest stage of the nexus probe. However, no device registers - * are touched until the actual h/w is probed later on during the - * MacIO probe. At that point, any interrupt sources that were allocated - * prior to this are activated. */ #include <sys/param.h> @@ -45,6 +39,7 @@ #include <sys/bus.h> #include <sys/conf.h> #include <sys/kernel.h> +#include <sys/rman.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/openfirm.h> @@ -60,67 +55,35 @@ #include <vm/vm.h> #include <vm/pmap.h> -#include <sys/rman.h> - #include <powerpc/powermac/hrowpicvar.h> #include "pic_if.h" /* - * Device interface. - */ -static void hrowpic_identify(driver_t *, device_t); -static int hrowpic_probe(device_t); -static int hrowpic_attach(device_t); - -/* - * PIC interface. - */ -static struct resource *hrowpic_allocate_intr(device_t, device_t, int *, - u_long, u_int); -static int hrowpic_setup_intr(device_t, device_t, - struct resource *, int, driver_filter_t, - driver_intr_t, void *, void **); -static int hrowpic_teardown_intr(device_t, device_t, - struct resource *, void *); -static int hrowpic_release_intr(device_t dev, device_t, int, - struct resource *res); - -/* * MacIO interface */ -static int hrowpic_macio_probe(device_t); -static int hrowpic_macio_attach(device_t); - -/* - * Local routines - */ -static void hrowpic_intr(void); -static void hrowpic_ext_enable_irq(uintptr_t); -static void hrowpic_ext_disable_irq(uintptr_t); -static void hrowpic_toggle_irq(struct hrowpic_softc *sc, int, int); +static int hrowpic_probe(device_t); +static int hrowpic_attach(device_t); -/* - * Interrupt controller softc. There should only be one. - */ -static struct hrowpic_softc *hpicsoftc; +static void hrowpic_dispatch(device_t, struct trapframe *); +static void hrowpic_enable(device_t, u_int, u_int); +static void hrowpic_eoi(device_t, u_int); +static void hrowpic_mask(device_t, u_int); +static void hrowpic_unmask(device_t, u_int); -/* - * Driver methods. - */ static device_method_t hrowpic_methods[] = { /* Device interface */ - DEVMETHOD(device_identify, hrowpic_identify), DEVMETHOD(device_probe, hrowpic_probe), DEVMETHOD(device_attach, hrowpic_attach), /* PIC interface */ - DEVMETHOD(pic_allocate_intr, hrowpic_allocate_intr), - DEVMETHOD(pic_setup_intr, hrowpic_setup_intr), - DEVMETHOD(pic_teardown_intr, hrowpic_teardown_intr), - DEVMETHOD(pic_release_intr, hrowpic_release_intr), + DEVMETHOD(pic_dispatch, hrowpic_dispatch), + DEVMETHOD(pic_enable, hrowpic_enable), + DEVMETHOD(pic_eoi, hrowpic_eoi), + DEVMETHOD(pic_mask, hrowpic_mask), + DEVMETHOD(pic_unmask, hrowpic_unmask), - { 0, 0 } + { 0, 0 }, }; static driver_t hrowpic_driver = { @@ -131,39 +94,48 @@ static driver_t hrowpic_driver = { static devclass_t hrowpic_devclass; -DRIVER_MODULE(hrowpic, nexus, hrowpic_driver, hrowpic_devclass, 0, 0); +DRIVER_MODULE(hrowpic, macio, hrowpic_driver, hrowpic_devclass, 0, 0); -static void -hrowpic_identify(driver_t *driver, device_t parent) +static uint32_t +hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank) { - phandle_t chosen, pic; - char type[40]; + if (bank == HPIC_PRIMARY) + reg += HPIC_1ST_OFFSET; - chosen = OF_finddevice("/chosen"); - if (chosen == -1) - return; + return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); +} - if (OF_getprop(chosen, "interrupt-controller", &pic, 4) != 4) - return; +static void +hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank, + uint32_t val) +{ - OF_getprop(pic, "compatible", type, sizeof(type)); - if (strcmp(type, "heathrow")) - return; + if (bank == HPIC_PRIMARY) + reg += HPIC_1ST_OFFSET; + + bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); - BUS_ADD_CHILD(parent, 0, "hrowpic", 0); + /* XXX Issue a read to force the write to complete. */ + bus_space_read_4(sc->sc_bt, sc->sc_bh, reg); } static int hrowpic_probe(device_t dev) { - char *name; - - name = nexus_get_name(dev); + const char *type = ofw_bus_get_type(dev); - if (strcmp(name, "hrowpic")) + /* + * OpenPIC cells have a type of "open-pic", so this + * is sufficient to identify a Heathrow cell + */ + if (strcmp(type, "interrupt-controller") != 0) return (ENXIO); - - device_set_desc(dev, "Heathrow interrupt controller"); + + /* + * The description was already printed out in the nexus + * probe, so don't do it again here + */ + device_set_desc(dev, "Heathrow MacIO interrupt controller"); return (0); } @@ -173,159 +145,36 @@ hrowpic_attach(device_t dev) struct hrowpic_softc *sc; sc = device_get_softc(dev); + sc->sc_dev = dev; - sc->sc_rman.rm_type = RMAN_ARRAY; - sc->sc_rman.rm_descr = device_get_nameunit(dev); + sc->sc_rrid = 0; + sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid, + RF_ACTIVE); - if (rman_init(&sc->sc_rman) != 0 || - rman_manage_region(&sc->sc_rman, 0, HROWPIC_IRQMAX-1) != 0) { - device_printf(dev, "could not set up resource management"); + if (sc->sc_rres == NULL) { + device_printf(dev, "Could not alloc mem resource!\n"); return (ENXIO); - } - - nexus_install_intcntlr(dev); - intr_init(hrowpic_intr, HROWPIC_IRQMAX, hrowpic_ext_enable_irq, - hrowpic_ext_disable_irq); - - KASSERT(hpicsoftc == NULL, ("hrowpic: h/w already probed")); - hpicsoftc = sc; - - return (0); -} - -/* - * PIC interface - */ -static struct resource * -hrowpic_allocate_intr(device_t picdev, device_t child, int *rid, u_long intr, - u_int flags) -{ - struct hrowpic_softc *sc; - struct resource *rv; - int needactivate; - - sc = device_get_softc(picdev); - needactivate = flags & RF_ACTIVE; - flags &= ~RF_ACTIVE; - - rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child); - if (rv == NULL) { - device_printf(picdev, "interrupt reservation failed for %s\n", - device_get_nameunit(child)); - return (NULL); } - rman_set_rid(rv, *rid); - - return (rv); -} -static int -hrowpic_setup_intr(device_t picdev, device_t child, struct resource *res, - int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, - void **cookiep) -{ - struct hrowpic_softc *sc; - u_long start; - int error; - - sc = device_get_softc(picdev); - start = rman_get_start(res); - - if ((rman_get_flags(res) & RF_SHAREABLE) == 0) - flags |= INTR_EXCL; + sc->sc_bt = rman_get_bustag(sc->sc_rres); + sc->sc_bh = rman_get_bushandle(sc->sc_rres); /* - * We depend here on rman_activate_resource() being idempotent. - */ - error = rman_activate_resource(res); - if (error) - return (error); - - error = inthand_add(device_get_nameunit(child), start, filt, intr, arg, - flags, cookiep); - - if (!error) { - /* - * Record irq request, and enable if h/w has been probed - */ - sc->sc_irq[start] = 1; - if (sc->sc_memr) { - hrowpic_toggle_irq(sc, start, 1); - } - } - - return (error); -} - -static int -hrowpic_teardown_intr(device_t picdev, device_t child, struct resource *res, - void *ih) -{ - int error; - - error = rman_deactivate_resource(res); - if (error) - return (error); - - error = inthand_remove(rman_get_start(res), ih); - - return (error); -} - -static int -hrowpic_release_intr(device_t picdev, device_t child, int rid, - struct resource *res) -{ - int error; - - if (rman_get_flags(res) & RF_ACTIVE) { - error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res); - if (error) - return (error); - } - - return (rman_release_resource(res)); -} - -/* - * Interrupt interface - */ -static void -hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank, - u_int32_t val) -{ - if (bank == HPIC_PRIMARY) - reg += HPIC_1ST_OFFSET; - - bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); - - /* - * XXX Issue a read to force the write to complete - */ - bus_space_read_4(sc->sc_bt, sc->sc_bh, reg); -} - -static u_int32_t -hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank) -{ - if (bank == HPIC_PRIMARY) - reg += HPIC_1ST_OFFSET; - - return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); -} - -static void -hrowpic_clear_all(struct hrowpic_softc *sc) -{ - /* * Disable all interrupt sources and clear outstanding interrupts */ hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_PRIMARY, 0); hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY, 0xffffffff); hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_SECONDARY, 0); hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY, 0xffffffff); + + powerpc_register_pic(dev); + return (0); } +/* + * Local routines + */ + static void hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable) { @@ -349,143 +198,74 @@ hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable) hrowpic_write_reg(sc, HPIC_ENABLE, roffset, sc->sc_softreg[roffset]); } +/* + * PIC I/F methods. + */ + static void -hrowpic_intr(void) +hrowpic_dispatch(device_t dev, struct trapframe *tf) { - int irq_lo, irq_hi; - int i; struct hrowpic_softc *sc; + uint64_t mask; + uint32_t reg; + u_int irq; - sc = hpicsoftc; - - /* - * Loop through both interrupt sources until they are empty. - * XXX simplistic code, far from optimal. - */ - do { - irq_lo = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY); - if (irq_lo) { - hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY, - irq_lo); - for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) { - if (irq_lo & (1 << i)) { - /* - * Disable IRQ and call handler - */ - hrowpic_toggle_irq(sc, i, 0); - intr_handle(i); - } - } - - } - - irq_hi = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY); - if (irq_hi) { - hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY, - irq_hi); - for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) { - if (irq_hi & (1 << i)) { - /* - * Disable IRQ and call handler - */ - hrowpic_toggle_irq(sc, - i + HROWPIC_IRQ_REGNUM, 0); - intr_handle(i + HROWPIC_IRQ_REGNUM); - } - } + sc = device_get_softc(dev); + while (1) { + mask = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY); + reg = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY); + mask = (mask << 32) | reg; + if (mask == 0) + break; + + irq = 0; + while (irq < HROWPIC_IRQMAX) { + if (mask & 1) + powerpc_dispatch_intr(sc->sc_vector[irq], tf); + mask >>= 1; + irq++; } - } while (irq_lo && irq_hi); + } } static void -hrowpic_ext_enable_irq(uintptr_t irq) +hrowpic_enable(device_t dev, u_int irq, u_int vector) { - hrowpic_toggle_irq(hpicsoftc, irq, 1); + struct hrowpic_softc *sc; + + sc = device_get_softc(dev); + sc->sc_vector[irq] = vector; + hrowpic_toggle_irq(sc, irq, 1); } static void -hrowpic_ext_disable_irq(uintptr_t irq) +hrowpic_eoi(device_t dev __unused, u_int irq __unused) { - hrowpic_toggle_irq(hpicsoftc, irq, 0); -} - - -/* - * MacIO interface - */ - -static device_method_t hrowpic_macio_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, hrowpic_macio_probe), - DEVMETHOD(device_attach, hrowpic_macio_attach), - - { 0, 0 }, -}; - -static driver_t hrowpic_macio_driver = { - "hrowpicmacio", - hrowpic_macio_methods, - 0 -}; - -static devclass_t hrowpic_macio_devclass; + struct hrowpic_softc *sc; + int bank; -DRIVER_MODULE(hrowpicmacio, macio, hrowpic_macio_driver, - hrowpic_macio_devclass, 0, 0); + sc = device_get_softc(dev); + bank = (irq >= 32) ? HPIC_SECONDARY : HPIC_PRIMARY ; + hrowpic_write_reg(sc, HPIC_CLEAR, bank, 1U << (irq & 0x1f)); +} -static int -hrowpic_macio_probe(device_t dev) +static void +hrowpic_mask(device_t dev, u_int irq) { - const char *type = ofw_bus_get_type(dev); - - /* - * OpenPIC cells have a type of "open-pic", so this - * is sufficient to identify a Heathrow cell - */ - if (strcmp(type, "interrupt-controller") != 0) - return (ENXIO); + struct hrowpic_softc *sc; + int bank; - /* - * The description was already printed out in the nexus - * probe, so don't do it again here - */ - device_set_desc(dev, "Heathrow MacIO interrupt cell"); - device_quiet(dev); - return (0); + sc = device_get_softc(dev); + hrowpic_toggle_irq(sc, irq, 0); + bank = (irq >= 32) ? HPIC_SECONDARY : HPIC_PRIMARY ; + hrowpic_write_reg(sc, HPIC_CLEAR, bank, 1U << (irq & 0x1f)); } -static int -hrowpic_macio_attach(device_t dev) +static void +hrowpic_unmask(device_t dev, u_int irq) { - struct hrowpic_softc *sc = hpicsoftc; - int rid; - int i; - - KASSERT(sc != NULL, ("pic not nexus-probed\n")); - sc->sc_maciodev = dev; - - rid = 0; - sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - - if (sc->sc_memr == NULL) { - device_printf(dev, "Could not alloc mem resource!\n"); - return (ENXIO); - } - - sc->sc_bt = rman_get_bustag(sc->sc_memr); - sc->sc_bh = rman_get_bushandle(sc->sc_memr); - - hrowpic_clear_all(sc); - - /* - * Enable all IRQs that were requested before the h/w - * was probed - */ - for (i = 0; i < HROWPIC_IRQMAX; i++) - if (sc->sc_irq[i]) { - hrowpic_toggle_irq(sc, i, 1); - } + struct hrowpic_softc *sc; - return (0); + sc = device_get_softc(dev); + hrowpic_toggle_irq(sc, irq, 1); } |