]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/powerpc/powerpc/openpic.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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.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         /* Reset the PIC */
104         x = openpic_read(sc, OPENPIC_CONFIG);
105         x |= OPENPIC_CONFIG_RESET;
106         openpic_write(sc, OPENPIC_CONFIG, x);
107
108         while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) {
109                 powerpc_sync();
110                 DELAY(100);
111         }
112
113         x = openpic_read(sc, OPENPIC_FEATURE);
114         switch (x & OPENPIC_FEATURE_VERSION_MASK) {
115         case 1:
116                 sc->sc_version = "1.0";
117                 break;
118         case 2:
119                 sc->sc_version = "1.2";
120                 break;
121         case 3:
122                 sc->sc_version = "1.3";
123                 break;
124         default:
125                 sc->sc_version = "unknown";
126                 break;
127         }
128
129         sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >>
130             OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1;
131         sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
132             OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1;
133
134         /*
135          * PSIM seems to report 1 too many IRQs and CPUs
136          */
137         if (sc->sc_psim) {
138                 sc->sc_nirq--;
139                 sc->sc_ncpu--;
140         }
141
142         if (bootverbose)
143                 device_printf(dev,
144                     "Version %s, supports %d CPUs and %d irqs\n",
145                     sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
146
147         for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
148                 openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15);
149
150         /* Reset and disable all interrupts. */
151         for (irq = 0; irq < sc->sc_nirq; irq++) {
152                 x = irq;                /* irq == vector. */
153                 x |= OPENPIC_IMASK;
154                 x |= OPENPIC_POLARITY_POSITIVE;
155                 x |= OPENPIC_SENSE_LEVEL;
156                 x |= 8 << OPENPIC_PRIORITY_SHIFT;
157                 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
158         }
159
160         /* Reset and disable all IPIs. */
161         for (ipi = 0; ipi < 4; ipi++) {
162                 x = sc->sc_nirq + ipi;
163                 x |= OPENPIC_IMASK;
164                 x |= 15 << OPENPIC_PRIORITY_SHIFT;
165                 openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x);
166         }
167
168         /* we don't need 8259 passthrough mode */
169         x = openpic_read(sc, OPENPIC_CONFIG);
170         x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
171         openpic_write(sc, OPENPIC_CONFIG, x);
172
173         /* send all interrupts to cpu 0 */
174         for (irq = 0; irq < sc->sc_nirq; irq++)
175                 openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
176
177         /* clear all pending interrupts */
178         for (irq = 0; irq < sc->sc_nirq; irq++) {
179                 (void)openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid)));
180                 openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
181         }
182
183         for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
184                 openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0);
185
186         powerpc_register_pic(dev, sc->sc_nirq);
187
188         return (0);
189 }
190
191 /*
192  * PIC I/F methods
193  */
194
195 void
196 openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
197     enum intr_polarity pol)
198 {
199         struct openpic_softc *sc;
200         uint32_t x;
201
202         sc = device_get_softc(dev);
203         x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
204         if (pol == INTR_POLARITY_LOW)
205                 x &= ~OPENPIC_POLARITY_POSITIVE;
206         else
207                 x |= OPENPIC_POLARITY_POSITIVE;
208         if (trig == INTR_TRIGGER_EDGE)
209                 x &= ~OPENPIC_SENSE_LEVEL;
210         else
211                 x |= OPENPIC_SENSE_LEVEL;
212         openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
213 }
214
215 void
216 openpic_dispatch(device_t dev, struct trapframe *tf)
217 {
218         struct openpic_softc *sc;
219         u_int cpuid, vector;
220
221         CTR1(KTR_INTR, "%s: got interrupt", __func__);
222
223         cpuid = PCPU_GET(cpuid);
224         sc = device_get_softc(dev);
225
226         while (1) {
227                 vector = openpic_read(sc, OPENPIC_PCPU_IACK(cpuid));
228                 vector &= OPENPIC_VECTOR_MASK;
229                 if (vector == 255)
230                         break;
231                 powerpc_dispatch_intr(vector, tf);
232         }
233 }
234
235 void
236 openpic_enable(device_t dev, u_int irq, u_int vector)
237 {
238         struct openpic_softc *sc;
239         uint32_t x;
240
241         sc = device_get_softc(dev);
242         if (irq < sc->sc_nirq) {
243                 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
244                 x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
245                 x |= vector;
246                 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
247         } else {
248                 x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
249                 x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
250                 x |= vector;
251                 openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
252         }
253 }
254
255 void
256 openpic_eoi(device_t dev, u_int irq __unused)
257 {
258         struct openpic_softc *sc;
259
260         sc = device_get_softc(dev);
261         openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
262 }
263
264 void
265 openpic_ipi(device_t dev, u_int cpu)
266 {
267         struct openpic_softc *sc;
268
269         sc = device_get_softc(dev);
270         openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0),
271             1u << cpu);
272 }
273
274 void
275 openpic_mask(device_t dev, u_int irq)
276 {
277         struct openpic_softc *sc;
278         uint32_t x;
279
280         sc = device_get_softc(dev);
281         if (irq < sc->sc_nirq) {
282                 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
283                 x |= OPENPIC_IMASK;
284                 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
285         } else {
286                 x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
287                 x |= OPENPIC_IMASK;
288                 openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
289         }
290         openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0);
291 }
292
293 void
294 openpic_unmask(device_t dev, u_int irq)
295 {
296         struct openpic_softc *sc;
297         uint32_t x;
298
299         sc = device_get_softc(dev);
300         if (irq < sc->sc_nirq) {
301                 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
302                 x &= ~OPENPIC_IMASK;
303                 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
304         } else {
305                 x = openpic_read(sc, OPENPIC_IPI_VECTOR(0));
306                 x &= ~OPENPIC_IMASK;
307                 openpic_write(sc, OPENPIC_IPI_VECTOR(0), x);
308         }
309 }