1 /* $NetBSD: pic_discovery.c,v 1.1.2.1 2007/05/11 05:51:48 matt Exp $ */
4 * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
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"
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>
96 #include <machine/db_machdep.h>
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)
110 # define DPRINTF(x) do { if (intrdebug) printf x ; } while (0)
111 # define DPRINTFN(n, x) do { if (intrdebug > (n)) printf x ; } while (0)
113 # define STATIC static
115 # define DPRINTFN(n, x)
119 # define DIAGPRF(x) printf x
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];
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];
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 */
176 gpp_get_irq(struct pic_ops
*pic
)
178 struct gpppic_ops
* const gpp
= (void *)pic
;
181 int maybe_priority
= IPL_NONE
;
184 mask
= bus_space_read_4(&gpp
->gpp_memt
, gpp
->gpp_memh
, GT_GPP_Interrupt_Cause
);
186 mask
= bus_space_read_4(&gpp
->gpp_memt
, gpp
->gpp_memh
, GT_GPP_Value
);
188 mask
&= gpp
->gpp_interrupt_mask
;
193 int irq
= 32 - __builtin_clz(mask
);
194 if (gpp
->gpp_priority
[irq
] > maybe_irq
) {
196 maybe_priority
= gpp
->gpp_priority
[irq
];
197 if (maybe_priority
> gpp
->gpp_maxpriority
[irq
])
203 * We now have the highest priority IRQ.
205 KASSERT(maybe_irq
>= 0);
207 mask
= 1 << maybe_irq
;
208 bus_space_write_4(&gpp
->gpp_memt
, gpp
->gpp_memh
, GT_GPP_Interrupt_Cause
, mask
);
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);
222 KASSERT(type
== IST_EDGE
);
224 KASSERT(type
== IST_LEVEL
);
228 * Set pin to input and active low.
230 val
= bus_space_read_4(gpp
->gpp_memt
, gpp
->gpp_memh
, GT_GPP_IO_Control
);
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
);
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.
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
;
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
);
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
);
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
;
287 gpp
= malloc(sizeof(*gpp
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
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
;
313 discovery_source_name(struct pic_ops
*pic
, int irq
, char *name
, size_t len
)
315 strlcpy(name
, discovery_intr_source_strings
[irq
], len
);
319 discovery_get_irq(struct pic_ops
*pic
)
321 struct discoverypic_ops
* const dsc
= (void *)pic
;
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
))
330 irq_base
= (mask
& CSC_SEL
) ? 32 : 0;
331 mask
&= dsc
->dsc_interrupt_mask
[(mask
& CSC_SEL
) ? 1 : 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
])
343 * We now have the highest priority IRQ (except it's cascaded).
345 KASSERT(maybe_irq
>= 0);
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);
356 KASSERT(type
== IST_EDGE
);
358 KASSERT(type
== IST_LEVEL
);
361 dsc
->dsc_priority
[irq
] = pri
;
364 * recalculate the maxpriority of an interrupt. This is highest
365 * priority interrupt from itself to irq 0.
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
;
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
);
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]);
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]);
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);
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]);
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]);
412 discovery_ack_irq(struct pic_ops
*pic
, int irq
)
417 discoverypic_setup(bus_space_tag_t memt
, bus_space_handle_t memh
)
419 struct discoverypic_ops
*dsc
;
422 dsc
= malloc(sizeof(*dsc
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
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
);