2 * Copyright (C) 2002 Benno Rice.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/param.h>
29 #include <sys/systm.h>
32 #include <sys/kernel.h>
34 #include <machine/bus.h>
35 #include <machine/intr.h>
36 #include <machine/intr_machdep.h>
37 #include <machine/md_var.h>
38 #include <machine/pio.h>
39 #include <machine/resource.h>
46 #include <machine/openpicreg.h>
47 #include <machine/openpicvar.h>
54 static u_int openpic_read(struct openpic_softc *, int);
55 static void openpic_write(struct openpic_softc *, int, u_int);
56 static int openpic_read_irq(struct openpic_softc *, int);
57 static void openpic_eoi(struct openpic_softc *, int);
58 static void openpic_enable_irq(struct openpic_softc *, int, int);
59 static void openpic_disable_irq(struct openpic_softc *, int);
60 static void openpic_set_priority(struct openpic_softc *, int, int);
61 static void openpic_intr(void);
62 static void openpic_ext_enable_irq(uintptr_t);
63 static void openpic_ext_disable_irq(uintptr_t);
65 /* XXX This limits us to one openpic */
66 static struct openpic_softc *openpic_softc;
69 * Called at nexus-probe time to allow interrupts to be enabled by
70 * devices that are probed before the OpenPIC h/w is probed.
73 openpic_early_attach(device_t dev)
75 struct openpic_softc *sc;
77 sc = device_get_softc(dev);
80 sc->sc_rman.rm_type = RMAN_ARRAY;
81 sc->sc_rman.rm_descr = device_get_nameunit(dev);
83 if (rman_init(&sc->sc_rman) != 0 ||
84 rman_manage_region(&sc->sc_rman, 0, OPENPIC_IRQMAX-1) != 0) {
85 device_printf(dev, "could not set up resource management");
89 intr_init(openpic_intr, OPENPIC_IRQMAX, openpic_ext_enable_irq,
90 openpic_ext_disable_irq);
92 sc->sc_early_done = 1;
98 openpic_attach(device_t dev)
100 struct openpic_softc *sc;
104 sc = device_get_softc(dev);
107 if (!sc->sc_early_done)
108 openpic_early_attach(dev);
110 x = openpic_read(sc, OPENPIC_FEATURE);
111 switch (x & OPENPIC_FEATURE_VERSION_MASK) {
113 sc->sc_version = "1.0";
116 sc->sc_version = "1.2";
119 sc->sc_version = "1.3";
122 sc->sc_version = "unknown";
126 sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >>
127 OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1;
128 sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
129 OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1;
132 * PSIM seems to report 1 too many IRQs
139 "Version %s, supports %d CPUs and %d irqs\n",
140 sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
142 /* disable all interrupts */
143 for (irq = 0; irq < sc->sc_nirq; irq++)
144 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
146 openpic_set_priority(sc, 0, 15);
148 /* we don't need 8259 passthrough mode */
149 x = openpic_read(sc, OPENPIC_CONFIG);
150 x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
151 openpic_write(sc, OPENPIC_CONFIG, x);
153 /* send all interrupts to cpu 0 */
154 for (irq = 0; irq < sc->sc_nirq; irq++)
155 openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
157 for (irq = 0; irq < sc->sc_nirq; irq++) {
160 x |= OPENPIC_POLARITY_POSITIVE;
161 x |= OPENPIC_SENSE_LEVEL;
162 x |= 8 << OPENPIC_PRIORITY_SHIFT;
163 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
167 /* XXX set spurious intr vector */
169 openpic_set_priority(sc, 0, 0);
171 /* clear all pending interrupts */
172 for (irq = 0; irq < sc->sc_nirq; irq++) {
173 openpic_read_irq(sc, 0);
177 /* enable pre-h/w reserved irqs, disable all others */
178 for (irq = 0; irq < sc->sc_nirq; irq++)
179 if (sc->sc_irqrsv[irq])
180 openpic_enable_irq(sc, irq, IST_LEVEL);
182 openpic_disable_irq(sc, irq);
192 openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
195 struct openpic_softc *sc;
199 sc = device_get_softc(dev);
200 needactivate = flags & RF_ACTIVE;
203 if (sc->sc_hwprobed && (intr > sc->sc_nirq)) {
204 device_printf(dev, "interrupt reservation %ld out of range\n",
209 rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
211 device_printf(dev, "interrupt reservation failed for %s\n",
212 device_get_nameunit(child));
215 rman_set_rid(rv, *rid);
217 if (bus_activate_resource(child, SYS_RES_IRQ, *rid, rv) != 0) {
219 "resource activation failed for %s\n",
220 device_get_nameunit(child));
221 rman_release_resource(rv);
230 openpic_setup_intr(device_t dev, device_t child, struct resource *res,
231 int flags, driver_intr_t *intr, void *arg, void **cookiep)
233 struct openpic_softc *sc;
237 sc = device_get_softc(dev);
238 start = rman_get_start(res);
241 device_printf(dev, "null interrupt resource from %s\n",
242 device_get_nameunit(child));
246 if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
250 * We depend here on rman_activate_resource() being idempotent.
252 error = rman_activate_resource(res);
256 error = inthand_add(device_get_nameunit(child), start, intr, arg,
260 openpic_enable_irq(sc, start, IST_LEVEL);
262 sc->sc_irqrsv[start] = 1;
268 openpic_teardown_intr(device_t dev, device_t child, struct resource *res,
273 error = rman_deactivate_resource(res);
277 error = inthand_remove(rman_get_start(res), ih);
283 openpic_release_intr(device_t dev, device_t child, int rid,
284 struct resource *res)
288 if (rman_get_flags(res) & RF_ACTIVE) {
289 error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
294 return (rman_release_resource(res));
302 openpic_read(struct openpic_softc *sc, int reg)
304 return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
308 openpic_write(struct openpic_softc *sc, int reg, u_int val)
310 bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
314 openpic_read_irq(struct openpic_softc *sc, int cpu)
316 return openpic_read(sc, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
320 openpic_eoi(struct openpic_softc *sc, int cpu)
322 openpic_write(sc, OPENPIC_EOI(cpu), 0);
326 openpic_enable_irq(struct openpic_softc *sc, int irq, int type)
330 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
331 x &= ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL | OPENPIC_SENSE_EDGE);
332 if (type == IST_LEVEL)
333 x |= OPENPIC_SENSE_LEVEL;
335 x |= OPENPIC_SENSE_EDGE;
336 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
340 openpic_disable_irq(struct openpic_softc *sc, int irq)
344 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
346 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
350 openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
354 x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu));
355 x &= ~OPENPIC_CPU_PRIORITY_MASK;
357 openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x);
363 struct openpic_softc *sc;
370 irq = openpic_read_irq(sc, 0);
376 openpic_disable_irq(sc, irq);
377 /*mtmsr(msr | PSL_EE);*/
379 /* do the interrupt thang */
386 irq = openpic_read_irq(sc, 0);
392 openpic_ext_enable_irq(uintptr_t irq)
394 if (!openpic_softc->sc_hwprobed)
397 openpic_enable_irq(openpic_softc, irq, IST_LEVEL);
401 openpic_ext_disable_irq(uintptr_t irq)
403 if (!openpic_softc->sc_hwprobed)
406 openpic_disable_irq(openpic_softc, irq);