xref: /freebsd/sys/powerpc/powerpc/openpic.c (revision ea906c4152774dff300bb26fbfc1e4188351c89a)
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$
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 
50 devclass_t openpic_devclass;
51 
52 /*
53  * Local routines
54  */
55 
56 static __inline uint32_t
57 openpic_read(struct openpic_softc *sc, u_int reg)
58 {
59 	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
60 }
61 
62 static __inline void
63 openpic_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 
68 static __inline void
69 openpic_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 
81 int
82 openpic_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 
183 void
184 openpic_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 
203 void
204 openpic_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 
229 void
230 openpic_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 
249 void
250 openpic_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 
258 void
259 openpic_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 
268 void
269 openpic_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 
287 void
288 openpic_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