Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / powerpc / marvell / pic_discovery.c
blobd418eb9120a2b6b31f0a564fe4f8527e9f747c64
1 /* $NetBSD: pic_discovery.c,v 1.1.2.1 2007/05/11 05:51:48 matt Exp $ */
3 /*
4 * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project by
18 * Allegro Networks, Inc., and Wasabi Systems, Inc.
19 * 4. The name of Allegro Networks, Inc. may not be used to endorse
20 * or promote products derived from this software without specific prior
21 * written permission.
22 * 5. The name of Wasabi Systems, Inc. may not be used to endorse
23 * or promote products derived from this software without specific prior
24 * written permission.
26 * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
27 * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
41 * extintr.c - external interrupt management for discovery
43 * Interrupts are software-prioritized and preempting,
44 * they are only actually masked when pending.
45 * this allows avoiding slow, off-CPU mask reprogramming for spl/splx.
46 * When a lower priority interrupt preempts a high one,
47 * it is pended and masked. Masks are re-enabled after service.
49 * `ci->ci_cpl' is a "priority level" not a bitmask.
50 * `irq' is a bit number in the 128 bit imask_t which reflects
51 * the GT-64260 Main Cause register pair (64 bits), and
52 * GPP Cause register (32 bits) interrupts.
54 * Intra IPL dispatch order is defined in cause_irq()
56 * Summary bits in cause registers are not valid IRQs
58 * Within a cause register bit vector ISRs are called in
59 * order of IRQ (descending).
61 * When IRQs are shared, ISRs are called in order on the queue
62 * (which is arbitrarily first-established-first-served).
64 * GT64260 GPP setup is for edge-triggered interrupts.
65 * We maintain a mask of level-triggered type IRQs
66 * and gather unlatched level from the GPP Value register.
68 * Software interrupts are just like regular IRQs,
69 * they are established, pended, and dispatched exactly the
70 * same as HW interrupts.
72 * 128 bit imask_t operations could be implemented with Altivec
73 * ("vand", "vor", etc however no "vcntlzw" or "vffs"....)
75 * creation Tue Feb 6 17:27:18 PST 2001 cliff
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: pic_discovery.c,v 1.1.2.1 2007/05/11 05:51:48 matt Exp $");
81 #include "opt_marvell.h"
82 #include "opt_kgdb.h"
84 #include <sys/param.h>
85 #include <sys/systm.h>
86 #include <sys/types.h>
87 #include <sys/malloc.h>
88 #include <sys/kernel.h>
90 #include <machine/psl.h>
91 #include <machine/bus.h>
92 #include <machine/cpu.h>
93 #include <machine/intr.h>
94 #include <powerpc/pic/picvar.h>
95 #ifdef KGDB
96 #include <machine/db_machdep.h>
97 #endif
98 #include <dev/marvell/gtreg.h>
99 #include <dev/marvell/gtvar.h>
100 #include <dev/marvell/gtintrreg.h>
102 #include <uvm/uvm_extern.h>
104 #if defined(DEBUG) && defined(DDB)
105 #endif
107 #ifdef DEBUG
108 # define STATIC
109 int intrdebug = 0;
110 # define DPRINTF(x) do { if (intrdebug) printf x ; } while (0)
111 # define DPRINTFN(n, x) do { if (intrdebug > (n)) printf x ; } while (0)
112 #else
113 # define STATIC static
114 # define DPRINTF(x)
115 # define DPRINTFN(n, x)
116 #endif
118 #ifdef DIAGNOSTIC
119 # define DIAGPRF(x) printf x
120 #else
121 # define DIAGPRF(x)
122 #endif
124 #define ILLEGAL_IRQ(x) (((x) < 0) || ((x) >= NIRQ) || \
125 ((1<<((x)&IMASK_BITMASK)) & imres.bits[(x)>>IMASK_WORDSHIFT]))
127 extern struct powerpc_bus_space gt_mem_bs_tag;
128 extern bus_space_handle_t gt_memh;
130 static const char intr_source_strings[NIRQ][16] = {
131 "unknown 0", "dev", "dma", "cpu",
132 "idma 01", "idma 23", "idma 45", "idma 67",
133 "timer 01", "timer 23", "timer 45", "timer 67",
134 "pci0-0", "pci0-1", "pci0-2", "pci0-3",
135 /*16*/ "pci1-0", "ecc", "pci1-1", "pci1-2",
136 "pci1-3", "pci0-outl", "pci0-outh", "pci1-outl",
137 "pci1-outh", "unknown 25", "pci0-inl", "pci0-inh",
138 "pci1-inl", "pci1-inh", "unknown 30", "unknown 31",
139 /*32*/ "ether 0", "ether 1", "ether 2", "unknown 35",
140 "sdma", "iic", "unknown 38", "brg",
141 "mpsc 0", "unknown 41", "mpsc 1", "comm",
142 "unknown 44", "unknown 45", "unknown 46", "unknown 47",
143 /*48*/ "unknown 48", "unknown 49", "unknown 50", "unknown 51",
144 "unknown 52", "unknown 53", "unknown 54", "unknown 55",
145 "gppsum 0", "gppsum 1", "gppsum 2", "gppsum 3",
146 "unknown 60", "unknown 61", "unknown 62", "unknown 63",
149 struct discovery_pic_ops {
150 struct pic_ops dsc_pic;
151 bus_space_tag_t dsc_memt;
152 bus_space_tag_t dsc_memh;
153 uint32_t dsc_interrupt_mask[2];
154 uint8_t dsc_priority[64];
155 uint8_t dsc_maxpriority[64];
158 struct gpp_pic_ops {
159 struct pic_ops gpp_pic;
160 bus_space_tag_t gpp_memt;
161 bus_space_handle_t gpp_memh;
162 uint32_t gpp_interrupt_mask;
163 uint8_t gpp_priority[32];
164 uint8_t gpp_maxpriority[32];
167 static void
168 gpp_source_name(struct pic_ops *pic, int irq, char *name, size_t len)
170 snprintf(name, len, "gpp %d", irq);
173 #define GPP_RES ~GT_MPP_INTERRUPTS /* from config */
175 static int
176 gpp_get_irq(struct pic_ops *pic)
178 struct gpppic_ops * const gpp = (void *)pic;
179 uint32_t mask;
180 int maybe_irq = -1;
181 int maybe_priority = IPL_NONE;
183 #ifdef GPP_EDGE
184 mask = bus_space_read_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Cause);
185 #else
186 mask = bus_space_read_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Value);
187 #endif
188 mask &= gpp->gpp_interrupt_mask;
189 if (mask == 0)
190 return NO_IRQ;
192 while (mask != 0) {
193 int irq = 32 - __builtin_clz(mask);
194 if (gpp->gpp_priority[irq] > maybe_irq) {
195 maybe_irq = irq;
196 maybe_priority = gpp->gpp_priority[irq];
197 if (maybe_priority > gpp->gpp_maxpriority[irq])
198 break;
200 mask &= ~(1 << irq);
203 * We now have the highest priority IRQ.
205 KASSERT(maybe_irq >= 0);
206 #ifdef GPP_EDGE
207 mask = 1 << maybe_irq;
208 bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Cause, mask);
209 #endif
211 return maybe_irq;
214 static void
215 gpp_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
217 struct gpppic_ops * const gpp = (void *)pic;
218 const uint32_t mask = 1 << irq;
220 KASSERT((unsigned) irq < 32);
221 #ifdef GPP_EDGE
222 KASSERT(type == IST_EDGE);
223 #else
224 KASSERT(type == IST_LEVEL);
225 #endif
228 * Set pin to input and active low.
230 val = bus_space_read_4(gpp->gpp_memt, gpp->gpp_memh, GT_GPP_IO_Control);
231 val &= ~mask;
232 bus_space_write_4(gpp->gpp_memt, gpp->gpp_memh, GT_GPP_IO_Control, val);
234 val = bus_space_read_4(gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Level_Control);
235 val |= mask;
236 bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Level_Control, val);
238 gpp->gpp_priority[irq] = pri;
241 * recalculate the maxpriority of an interrupt. This is highest
242 * priority interrupt from itself to gpp0.
244 pri = IPL_NONE;
245 for (i = 0; i < __arraycount(gpp->gpp_priority); i++) {
246 if (gpp->gpp_priority[i] > pri)
247 pri = gpp->gpp_priority[i];
248 gpp->gpp_maxpriority[i] = pri;
252 static void
253 gpp_enable_irq(struct pic_ops *pic, int irq, int type)
255 struct gpppic_ops * const gpp = (void *)pic;
256 const uint32_t mask = 1 << irq;
258 KASSERT(type == IST_LEVEL);
259 KASSERT(gpp->gpp_priority[irq] != IPL_NONE);
260 gpp->gpp_interrupt_mask |= mask;
261 bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Mask,
262 gpp->gpp_interrupt_mask);
265 static void
266 gpp_disable_irq(struct pic_ops *pic, int irq)
268 struct gpppic_ops * const gpp = (void *)pic;
269 const uint32_t mask = 1 << irq;
271 gpp->gpp_interrupt_mask &= ~mask;
272 bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Mask,
273 gpp->gpp_interrupt_mask);
276 static void
277 gpp_ack_irq(struct pic_ops *pic, int irq)
281 static struct pic_ops *
282 gpp_pic_setup(bus_space_tag_t memt, bus_space_handle_t memh)
284 struct gpppic_ops * gpp;
285 uint32_t val;
287 gpp = malloc(sizeof(*gpp), M_DEVBUF, M_NOWAIT|M_ZERO);
288 if (!gpp)
289 panic("gpp_pic_setup: malloc(%zu) failed", sizeof(*gpp));
291 gpp->gpp_memt = memt;
292 gpp->gpp_memh = memh;
293 gpp->gpp_pic.pic_get_irq = gpp_get_irq;
294 gpp->gpp_pic.pic_enable_irq = gpp_enable_irq;
295 gpp->gpp_pic.pic_reenable_irq = gpp_enable_irq;
296 gpp->gpp_pic.pic_disable_irq = gpp_disable_irq;
297 gpp->gpp_pic.pic_ack_irq = gpp_ack_irq;
298 gpp->gpp_pic.pic_establish_irq = gpp_establish_irq;
299 gpp->gpp_pic.pic_source_name = gpp_source_name;
302 * Force GPP interrupts to be level sensitive.
304 val = bus_space_read_4(&gpp->gpp_memt, gpp->gpp_memh, 0xf300);
305 bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, 0xf300, val | 0x400);
307 pic_add(&gpp->gpp_pic);
309 return &gpp->gpp_pic;
312 static void
313 discovery_source_name(struct pic_ops *pic, int irq, char *name, size_t len)
315 strlcpy(name, discovery_intr_source_strings[irq], len);
318 static int
319 discovery_get_irq(struct pic_ops *pic)
321 struct discoverypic_ops * const dsc = (void *)pic;
322 uint32_t mask;
323 int irq_base = 0;
324 int maybe_irq = -1;
325 int maybe_priority = IPL_NONE;
327 mask = bus_space_read_4(&dsc->dsc_memt, dsc->dsc_memh, ICR_CSC);
328 if (!(mask & CSC_STAT))
329 return NO_IRQ;
330 irq_base = (mask & CSC_SEL) ? 32 : 0;
331 mask &= dsc->dsc_interrupt_mask[(mask & CSC_SEL) ? 1 : 0];
332 while (mask != 0) {
333 int irq = 32 - __builtin_clz(mask);
334 if (dsc->dsc_priority[irq_base + irq] > maybe_irq) {
335 maybe_irq = irq_base + irq;
336 maybe_priority = dsc->dsc_priority[irq_base + irq];
337 if (maybe_priority > dsc->dsc_maxpriority[irq_base + irq])
338 break;
340 mask &= ~(1 << irq);
343 * We now have the highest priority IRQ (except it's cascaded).
345 KASSERT(maybe_irq >= 0);
346 return maybe_irq;
349 static void
350 discovery_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
352 struct discoverypic_ops * const dsc = (void *)pic;
354 KASSERT((unsigned) irq < 32);
355 #ifdef GPP_EDGE
356 KASSERT(type == IST_EDGE);
357 #else
358 KASSERT(type == IST_LEVEL);
359 #endif
361 dsc->dsc_priority[irq] = pri;
364 * recalculate the maxpriority of an interrupt. This is highest
365 * priority interrupt from itself to irq 0.
367 pri = IPL_NONE;
368 for (i = 0; i < __arraycount(dsc->dsc_priority); i++) {
369 if (dsc->dsc_priority[i] > pri)
370 pri = dsc->dsc_priority[i];
371 dsc->dsc_maxpriority[i] = pri;
375 static void
376 discovery_enable_irq(struct pic_ops *pic, int irq, int type)
378 struct discoverypic_ops * const dsc = (void *)pic;
379 const uint32_t mask = 1 << (irq & 31);
381 KASSERT(type == IST_LEVEL);
382 KASSERT(dsc->dsc_priority[irq] != IPL_NONE);
383 if (irq < 32) {
384 dsc->dsc_interrupt_mask[0] |= mask;
385 bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
386 ICR_MIC_LO, dsc->dsc_interrupt_mask[0]);
387 } else {
388 dsc->dsc_interrupt_mask[1] |= mask;
389 bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
390 ICR_MIC_HI, dsc->dsc_interrupt_mask[1]);
394 static void
395 discovery_disable_irq(struct pic_ops *pic, int irq)
397 struct discoverypic_ops * const dsc = (void *)pic;
398 const uint32_t mask = 1 << (irq & 31);
400 if (irq < 32) {
401 dsc->dsc_interrupt_mask[0] &= ~mask;
402 bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
403 ICR_MIC_LO, dsc->dsc_interrupt_mask[0]);
404 } else {
405 dsc->dsc_interrupt_mask[1] &= ~mask;
406 bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
407 ICR_MIC_HI, dsc->dsc_interrupt_mask[1]);
411 static void
412 discovery_ack_irq(struct pic_ops *pic, int irq)
416 void
417 discoverypic_setup(bus_space_tag_t memt, bus_space_handle_t memh)
419 struct discoverypic_ops *dsc;
420 uint32_t val;
422 dsc = malloc(sizeof(*dsc), M_DEVBUF, M_NOWAIT|M_ZERO);
423 if (!dsc)
424 panic("dsc_pic_setup: malloc(%zu) failed", sizeof(*dsc));
426 dsc->dsc_memt = memt;
427 dsc->dsc_memh = memh;
428 dsc->dsc_pic.pic_get_irq = dsc_get_irq;
429 dsc->dsc_pic.pic_enable_irq = dsc_enable_irq;
430 dsc->dsc_pic.pic_reenable_irq = dsc_enable_irq;
431 dsc->dsc_pic.pic_disable_irq = dsc_disable_irq;
432 dsc->dsc_pic.pic_ack_irq = dsc_ack_irq;
433 dsc->dsc_pic.pic_establish_irq = dsc_establish_irq;
434 dsc->dsc_pic.pic_source_name = dsc_source_name;
436 pic_add(&dsc->dsc_pic);
437 KASSERT(dsc->dsc_pic.pic_intrbase == 0);
439 pic = dscpic_setup(memt, memh);
440 intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP7_0,
441 IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
442 intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP15_8,
443 IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
444 intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP23_16,
445 IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
446 intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP31_24,
447 IST_LEVEL, IPL_NONE, pic_handle_intr, pic);