openpic.c revision 209299
1139825Simp/*-
299654Sbenno * Copyright (C) 2002 Benno Rice.
399654Sbenno * All rights reserved.
499654Sbenno *
599654Sbenno * Redistribution and use in source and binary forms, with or without
699654Sbenno * modification, are permitted provided that the following conditions
799654Sbenno * are met:
899654Sbenno * 1. Redistributions of source code must retain the above copyright
999654Sbenno *    notice, this list of conditions and the following disclaimer.
1099654Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1199654Sbenno *    notice, this list of conditions and the following disclaimer in the
1299654Sbenno *    documentation and/or other materials provided with the distribution.
1399654Sbenno *
1499654Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
1599654Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1699654Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1799654Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1899654Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1999654Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2099654Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2199654Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2299654Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2399654Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2499654Sbenno *
2599654Sbenno * $FreeBSD: head/sys/powerpc/powerpc/openpic.c 209299 2010-06-18 14:16:24Z nwhitehorn $
2699654Sbenno */
2799654Sbenno
2899654Sbenno#include <sys/param.h>
2999654Sbenno#include <sys/systm.h>
3099654Sbenno#include <sys/bus.h>
3199654Sbenno#include <sys/conf.h>
3299654Sbenno#include <sys/kernel.h>
33171805Smarcel#include <sys/rman.h>
3499654Sbenno
3599654Sbenno#include <machine/bus.h>
3699654Sbenno#include <machine/intr.h>
3799654Sbenno#include <machine/intr_machdep.h>
3899654Sbenno#include <machine/md_var.h>
3999654Sbenno#include <machine/pio.h>
4099654Sbenno#include <machine/resource.h>
4199654Sbenno
4299654Sbenno#include <vm/vm.h>
4399654Sbenno#include <vm/pmap.h>
4499654Sbenno
4599654Sbenno#include <machine/openpicreg.h>
4699654Sbenno#include <machine/openpicvar.h>
4799654Sbenno
4899654Sbenno#include "pic_if.h"
4999654Sbenno
50171805Smarceldevclass_t openpic_devclass;
51171805Smarcel
5299654Sbenno/*
5399654Sbenno * Local routines
5499654Sbenno */
55209298Snwhitehornstatic int openpic_intr(void *arg);
5699654Sbenno
57171805Smarcelstatic __inline uint32_t
58171805Smarcelopenpic_read(struct openpic_softc *sc, u_int reg)
59171805Smarcel{
60171805Smarcel	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
61171805Smarcel}
6299654Sbenno
63171805Smarcelstatic __inline void
64171805Smarcelopenpic_write(struct openpic_softc *sc, u_int reg, uint32_t val)
6599654Sbenno{
66171805Smarcel	bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
67171805Smarcel}
68124469Sgrehan
69171805Smarcelstatic __inline void
70176208Smarcelopenpic_set_priority(struct openpic_softc *sc, int pri)
71171805Smarcel{
72176208Smarcel	u_int tpr;
73171805Smarcel	uint32_t x;
7499654Sbenno
75176208Smarcel	tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid));
76176208Smarcel	x = openpic_read(sc, tpr);
77176208Smarcel	x &= ~OPENPIC_TPR_MASK;
78171805Smarcel	x |= pri;
79176208Smarcel	openpic_write(sc, tpr, x);
80124469Sgrehan}
8199654Sbenno
82124469Sgrehanint
83124469Sgrehanopenpic_attach(device_t dev)
84124469Sgrehan{
85124469Sgrehan	struct openpic_softc *sc;
86178628Smarcel	u_int     cpu, ipi, irq;
87124469Sgrehan	u_int32_t x;
88103603Sgrehan
89124469Sgrehan	sc = device_get_softc(dev);
90171805Smarcel	sc->sc_dev = dev;
91103603Sgrehan
92171805Smarcel	sc->sc_rid = 0;
93171805Smarcel	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
94171805Smarcel	    RF_ACTIVE);
95124469Sgrehan
96171805Smarcel	if (sc->sc_memr == NULL) {
97171805Smarcel		device_printf(dev, "Could not alloc mem resource!\n");
98171805Smarcel		return (ENXIO);
99171805Smarcel	}
100171805Smarcel
101171805Smarcel	sc->sc_bt = rman_get_bustag(sc->sc_memr);
102171805Smarcel	sc->sc_bh = rman_get_bushandle(sc->sc_memr);
103171805Smarcel
104208149Snwhitehorn	/* Reset the PIC */
105208149Snwhitehorn	x = openpic_read(sc, OPENPIC_CONFIG);
106208149Snwhitehorn	x |= OPENPIC_CONFIG_RESET;
107208149Snwhitehorn	openpic_write(sc, OPENPIC_CONFIG, x);
108208149Snwhitehorn
109208149Snwhitehorn	while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) {
110208149Snwhitehorn		powerpc_sync();
111208149Snwhitehorn		DELAY(100);
112208149Snwhitehorn	}
113208149Snwhitehorn
114209298Snwhitehorn	/* Check if this is a cascaded PIC */
115209298Snwhitehorn	sc->sc_irq = 0;
116209298Snwhitehorn	sc->sc_intr = NULL;
117209298Snwhitehorn	if (resource_list_find(BUS_GET_RESOURCE_LIST(device_get_parent(dev),
118209298Snwhitehorn	    dev), SYS_RES_IRQ, 0) != NULL) {
119209298Snwhitehorn		sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ,
120209298Snwhitehorn		    &sc->sc_irq, RF_ACTIVE);
121209298Snwhitehorn
122209298Snwhitehorn		/* XXX Cascaded PICs pass NULL trapframes! */
123209298Snwhitehorn		bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_MISC | INTR_MPSAFE,
124209298Snwhitehorn		    openpic_intr, NULL, dev, &sc->sc_icookie);
125209298Snwhitehorn	}
126209298Snwhitehorn
127209298Snwhitehorn	/* Reset the PIC */
128209298Snwhitehorn	x = openpic_read(sc, OPENPIC_CONFIG);
129209298Snwhitehorn	x |= OPENPIC_CONFIG_RESET;
130209298Snwhitehorn	openpic_write(sc, OPENPIC_CONFIG, x);
131209298Snwhitehorn
132209298Snwhitehorn	while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) {
133209298Snwhitehorn		powerpc_sync();
134209298Snwhitehorn		DELAY(100);
135209298Snwhitehorn	}
136209298Snwhitehorn
137124469Sgrehan	x = openpic_read(sc, OPENPIC_FEATURE);
138124469Sgrehan	switch (x & OPENPIC_FEATURE_VERSION_MASK) {
13999654Sbenno	case 1:
14099654Sbenno		sc->sc_version = "1.0";
14199654Sbenno		break;
14299654Sbenno	case 2:
14399654Sbenno		sc->sc_version = "1.2";
14499654Sbenno		break;
14599654Sbenno	case 3:
14699654Sbenno		sc->sc_version = "1.3";
14799654Sbenno		break;
14899654Sbenno	default:
14999654Sbenno		sc->sc_version = "unknown";
15099654Sbenno		break;
15199654Sbenno	}
15299654Sbenno
153124469Sgrehan	sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >>
154110167Sbenno	    OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1;
155124469Sgrehan	sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
156110167Sbenno	    OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1;
15799654Sbenno
158111156Sgrehan	/*
159193909Sgrehan	 * PSIM seems to report 1 too many IRQs and CPUs
160111156Sgrehan	 */
161193909Sgrehan	if (sc->sc_psim) {
162111156Sgrehan		sc->sc_nirq--;
163193909Sgrehan		sc->sc_ncpu--;
164193909Sgrehan	}
165111156Sgrehan
166124469Sgrehan	if (bootverbose)
167124469Sgrehan		device_printf(dev,
168124469Sgrehan		    "Version %s, supports %d CPUs and %d irqs\n",
169124469Sgrehan		    sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
17099654Sbenno
171178628Smarcel	for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
172178628Smarcel		openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15);
173178628Smarcel
174176208Smarcel	/* Reset and disable all interrupts. */
175176208Smarcel	for (irq = 0; irq < sc->sc_nirq; irq++) {
176176208Smarcel		x = irq;                /* irq == vector. */
177176208Smarcel		x |= OPENPIC_IMASK;
178209299Snwhitehorn		x |= OPENPIC_POLARITY_NEGATIVE;
179176208Smarcel		x |= OPENPIC_SENSE_LEVEL;
180176208Smarcel		x |= 8 << OPENPIC_PRIORITY_SHIFT;
181176208Smarcel		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
182176208Smarcel	}
18399654Sbenno
184176208Smarcel	/* Reset and disable all IPIs. */
185176208Smarcel	for (ipi = 0; ipi < 4; ipi++) {
186176208Smarcel		x = sc->sc_nirq + ipi;
187176208Smarcel		x |= OPENPIC_IMASK;
188176208Smarcel		x |= 15 << OPENPIC_PRIORITY_SHIFT;
189176208Smarcel		openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x);
190176208Smarcel	}
19199654Sbenno
19299654Sbenno	/* we don't need 8259 passthrough mode */
19399654Sbenno	x = openpic_read(sc, OPENPIC_CONFIG);
19499654Sbenno	x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
19599654Sbenno	openpic_write(sc, OPENPIC_CONFIG, x);
19699654Sbenno
19799654Sbenno	/* send all interrupts to cpu 0 */
19899654Sbenno	for (irq = 0; irq < sc->sc_nirq; irq++)
19999654Sbenno		openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
20099654Sbenno
20199654Sbenno	/* clear all pending interrupts */
202103603Sgrehan	for (irq = 0; irq < sc->sc_nirq; irq++) {
203176208Smarcel		(void)openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid)));
204176208Smarcel		openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
20599654Sbenno	}
20699654Sbenno
207183028Smarcel	for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
208183028Smarcel		openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0);
209183028Smarcel
210176208Smarcel	powerpc_register_pic(dev, sc->sc_nirq);
21199654Sbenno
212209298Snwhitehorn	/* If this is not a cascaded PIC, it must be the root PIC */
213209298Snwhitehorn	if (sc->sc_intr == NULL)
214209298Snwhitehorn		root_pic = dev;
215209298Snwhitehorn
21699654Sbenno	return (0);
21799654Sbenno}
21899654Sbenno
21999654Sbenno/*
220171805Smarcel * PIC I/F methods
22199654Sbenno */
22299654Sbenno
223171805Smarcelvoid
224176918Smarcelopenpic_config(device_t dev, u_int irq, enum intr_trigger trig,
225176918Smarcel    enum intr_polarity pol)
226176918Smarcel{
227176918Smarcel	struct openpic_softc *sc;
228176918Smarcel	uint32_t x;
229176918Smarcel
230176918Smarcel	sc = device_get_softc(dev);
231176918Smarcel	x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
232176918Smarcel	if (pol == INTR_POLARITY_LOW)
233176918Smarcel		x &= ~OPENPIC_POLARITY_POSITIVE;
234176918Smarcel	else
235176918Smarcel		x |= OPENPIC_POLARITY_POSITIVE;
236176918Smarcel	if (trig == INTR_TRIGGER_EDGE)
237176918Smarcel		x &= ~OPENPIC_SENSE_LEVEL;
238176918Smarcel	else
239176918Smarcel		x |= OPENPIC_SENSE_LEVEL;
240176918Smarcel	openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
241176918Smarcel}
242176918Smarcel
243209298Snwhitehornstatic int
244209298Snwhitehornopenpic_intr(void *arg)
245209298Snwhitehorn{
246209298Snwhitehorn	device_t dev = (device_t)(arg);
247209298Snwhitehorn
248209298Snwhitehorn	/* XXX Cascaded PICs do not pass non-NULL trapframes! */
249209298Snwhitehorn	openpic_dispatch(dev, NULL);
250209298Snwhitehorn
251209298Snwhitehorn	return (FILTER_HANDLED);
252209298Snwhitehorn}
253209298Snwhitehorn
254176918Smarcelvoid
255171805Smarcelopenpic_dispatch(device_t dev, struct trapframe *tf)
25699654Sbenno{
257171805Smarcel	struct openpic_softc *sc;
258183028Smarcel	u_int cpuid, vector;
25999654Sbenno
260192532Sraj	CTR1(KTR_INTR, "%s: got interrupt", __func__);
261192532Sraj
262183028Smarcel	cpuid = PCPU_GET(cpuid);
263183028Smarcel	sc = device_get_softc(dev);
264178628Smarcel
265171805Smarcel	while (1) {
266183028Smarcel		vector = openpic_read(sc, OPENPIC_PCPU_IACK(cpuid));
267171805Smarcel		vector &= OPENPIC_VECTOR_MASK;
268171805Smarcel		if (vector == 255)
269171805Smarcel			break;
270171805Smarcel		powerpc_dispatch_intr(vector, tf);
271124469Sgrehan	}
27299654Sbenno}
27399654Sbenno
274171805Smarcelvoid
275171805Smarcelopenpic_enable(device_t dev, u_int irq, u_int vector)
27699654Sbenno{
277171805Smarcel	struct openpic_softc *sc;
278171805Smarcel	uint32_t x;
27999654Sbenno
28099654Sbenno	sc = device_get_softc(dev);
281176208Smarcel	if (irq < sc->sc_nirq) {
282176208Smarcel		x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
283176208Smarcel		x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
284176208Smarcel		x |= vector;
285176208Smarcel		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
286176208Smarcel	} else {
287176208Smarcel		x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
288176208Smarcel		x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
289176208Smarcel		x |= vector;
290176208Smarcel		openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
291176208Smarcel	}
29299654Sbenno}
29399654Sbenno
294171805Smarcelvoid
295171805Smarcelopenpic_eoi(device_t dev, u_int irq __unused)
29699654Sbenno{
297171805Smarcel	struct openpic_softc *sc;
29899654Sbenno
299171805Smarcel	sc = device_get_softc(dev);
300176208Smarcel	openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
30199654Sbenno}
30299654Sbenno
303171805Smarcelvoid
304176208Smarcelopenpic_ipi(device_t dev, u_int cpu)
305176208Smarcel{
306176208Smarcel	struct openpic_softc *sc;
307176208Smarcel
308176208Smarcel	sc = device_get_softc(dev);
309176208Smarcel	openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0),
310176208Smarcel	    1u << cpu);
311176208Smarcel}
312176208Smarcel
313176208Smarcelvoid
314171805Smarcelopenpic_mask(device_t dev, u_int irq)
31599654Sbenno{
316171805Smarcel	struct openpic_softc *sc;
317171805Smarcel	uint32_t x;
31899654Sbenno
319171805Smarcel	sc = device_get_softc(dev);
320176208Smarcel	if (irq < sc->sc_nirq) {
321176208Smarcel		x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
322176208Smarcel		x |= OPENPIC_IMASK;
323176208Smarcel		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
324176208Smarcel	} else {
325176208Smarcel		x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
326176208Smarcel		x |= OPENPIC_IMASK;
327176208Smarcel		openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
328176208Smarcel	}
329176208Smarcel	openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
33099654Sbenno}
33199654Sbenno
332171805Smarcelvoid
333171805Smarcelopenpic_unmask(device_t dev, u_int irq)
33499654Sbenno{
335171805Smarcel	struct openpic_softc *sc;
336171805Smarcel	uint32_t x;
33799654Sbenno
338171805Smarcel	sc = device_get_softc(dev);
339176208Smarcel	if (irq < sc->sc_nirq) {
340176208Smarcel		x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
341176208Smarcel		x &= ~OPENPIC_IMASK;
342176208Smarcel		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
343176208Smarcel	} else {
344176208Smarcel		x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
345176208Smarcel		x &= ~OPENPIC_IMASK;
346176208Smarcel		openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
347176208Smarcel	}
34899654Sbenno}
349