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