openpic.c revision 178628
1/*-
2 * Copyright (C) 2002 Benno Rice.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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.
24 *
25 * $FreeBSD: head/sys/powerpc/powerpc/openpic.c 178628 2008-04-27 22:33:43Z marcel $
26 */
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/bus.h>
31#include <sys/conf.h>
32#include <sys/kernel.h>
33#include <sys/rman.h>
34
35#include <machine/bus.h>
36#include <machine/intr.h>
37#include <machine/intr_machdep.h>
38#include <machine/md_var.h>
39#include <machine/pio.h>
40#include <machine/resource.h>
41
42#include <vm/vm.h>
43#include <vm/pmap.h>
44
45#include <machine/openpicreg.h>
46#include <machine/openpicvar.h>
47
48#include "pic_if.h"
49
50devclass_t openpic_devclass;
51
52/*
53 * Local routines
54 */
55
56static __inline uint32_t
57openpic_read(struct openpic_softc *sc, u_int reg)
58{
59	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
60}
61
62static __inline void
63openpic_write(struct openpic_softc *sc, u_int reg, uint32_t val)
64{
65	bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
66}
67
68static __inline void
69openpic_set_priority(struct openpic_softc *sc, int pri)
70{
71	u_int tpr;
72	uint32_t x;
73
74	tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid));
75	x = openpic_read(sc, tpr);
76	x &= ~OPENPIC_TPR_MASK;
77	x |= pri;
78	openpic_write(sc, tpr, x);
79}
80
81int
82openpic_attach(device_t dev)
83{
84	struct openpic_softc *sc;
85	u_int     cpu, ipi, irq;
86	u_int32_t x;
87
88	sc = device_get_softc(dev);
89	sc->sc_dev = dev;
90
91	sc->sc_rid = 0;
92	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
93	    RF_ACTIVE);
94
95	if (sc->sc_memr == NULL) {
96		device_printf(dev, "Could not alloc mem resource!\n");
97		return (ENXIO);
98	}
99
100	sc->sc_bt = rman_get_bustag(sc->sc_memr);
101	sc->sc_bh = rman_get_bushandle(sc->sc_memr);
102
103	x = openpic_read(sc, OPENPIC_FEATURE);
104	switch (x & OPENPIC_FEATURE_VERSION_MASK) {
105	case 1:
106		sc->sc_version = "1.0";
107		break;
108	case 2:
109		sc->sc_version = "1.2";
110		break;
111	case 3:
112		sc->sc_version = "1.3";
113		break;
114	default:
115		sc->sc_version = "unknown";
116		break;
117	}
118
119	sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >>
120	    OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1;
121	sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
122	    OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1;
123
124	/*
125	 * PSIM seems to report 1 too many IRQs
126	 */
127	if (sc->sc_psim)
128		sc->sc_nirq--;
129
130	if (bootverbose)
131		device_printf(dev,
132		    "Version %s, supports %d CPUs and %d irqs\n",
133		    sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
134
135	for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
136		openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15);
137
138	/* Reset and disable all interrupts. */
139	for (irq = 0; irq < sc->sc_nirq; irq++) {
140		x = irq;                /* irq == vector. */
141		x |= OPENPIC_IMASK;
142		x |= OPENPIC_POLARITY_POSITIVE;
143		x |= OPENPIC_SENSE_LEVEL;
144		x |= 8 << OPENPIC_PRIORITY_SHIFT;
145		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
146	}
147
148	/* Reset and disable all IPIs. */
149	for (ipi = 0; ipi < 4; ipi++) {
150		x = sc->sc_nirq + ipi;
151		x |= OPENPIC_IMASK;
152		x |= 15 << OPENPIC_PRIORITY_SHIFT;
153		openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x);
154	}
155
156	/* we don't need 8259 passthrough mode */
157	x = openpic_read(sc, OPENPIC_CONFIG);
158	x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
159	openpic_write(sc, OPENPIC_CONFIG, x);
160
161	/* send all interrupts to cpu 0 */
162	for (irq = 0; irq < sc->sc_nirq; irq++)
163		openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
164
165	for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
166		openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0);
167
168	/* clear all pending interrupts */
169	for (irq = 0; irq < sc->sc_nirq; irq++) {
170		(void)openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid)));
171		openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
172	}
173
174	powerpc_register_pic(dev, sc->sc_nirq);
175
176	return (0);
177}
178
179/*
180 * PIC I/F methods
181 */
182
183void
184openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
185    enum intr_polarity pol)
186{
187	struct openpic_softc *sc;
188	uint32_t x;
189
190	sc = device_get_softc(dev);
191	x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
192	if (pol == INTR_POLARITY_LOW)
193		x &= ~OPENPIC_POLARITY_POSITIVE;
194	else
195		x |= OPENPIC_POLARITY_POSITIVE;
196	if (trig == INTR_TRIGGER_EDGE)
197		x &= ~OPENPIC_SENSE_LEVEL;
198	else
199		x |= OPENPIC_SENSE_LEVEL;
200	openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
201}
202
203void
204openpic_dispatch(device_t dev, struct trapframe *tf)
205{
206	static int once = 0;
207	struct openpic_softc *sc;
208	u_int vector;
209
210	if (once == 0 && PCPU_GET(cpuid) != 0) {
211		printf("XXX: got interrupt!\n");
212		once++;
213	}
214
215	sc = device_get_softc(dev);
216	while (1) {
217		vector = openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid)));
218		vector &= OPENPIC_VECTOR_MASK;
219		if (vector == 255)
220			break;
221		if (once == 1 && PCPU_GET(cpuid) != 0) {
222			printf("XXX: got vector %u\n", vector);
223			once++;
224		}
225		powerpc_dispatch_intr(vector, tf);
226	}
227}
228
229void
230openpic_enable(device_t dev, u_int irq, u_int vector)
231{
232	struct openpic_softc *sc;
233	uint32_t x;
234
235	sc = device_get_softc(dev);
236	if (irq < sc->sc_nirq) {
237		x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
238		x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
239		x |= vector;
240		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
241	} else {
242		x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
243		x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
244		x |= vector;
245		openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
246	}
247}
248
249void
250openpic_eoi(device_t dev, u_int irq __unused)
251{
252	struct openpic_softc *sc;
253
254	sc = device_get_softc(dev);
255	openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
256}
257
258void
259openpic_ipi(device_t dev, u_int cpu)
260{
261	struct openpic_softc *sc;
262
263	sc = device_get_softc(dev);
264	openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0),
265	    1u << cpu);
266}
267
268void
269openpic_mask(device_t dev, u_int irq)
270{
271	struct openpic_softc *sc;
272	uint32_t x;
273
274	sc = device_get_softc(dev);
275	if (irq < sc->sc_nirq) {
276		x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
277		x |= OPENPIC_IMASK;
278		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
279	} else {
280		x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
281		x |= OPENPIC_IMASK;
282		openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
283	}
284	openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
285}
286
287void
288openpic_unmask(device_t dev, u_int irq)
289{
290	struct openpic_softc *sc;
291	uint32_t x;
292
293	sc = device_get_softc(dev);
294	if (irq < sc->sc_nirq) {
295		x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
296		x &= ~OPENPIC_IMASK;
297		openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
298	} else {
299		x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
300		x &= ~OPENPIC_IMASK;
301		openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
302	}
303}
304