1 /* $NetBSD: gdium_intr.c,v 1.1 2009/08/06 00:50:26 matt Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Platform-specific interrupt support for the Algorithmics P-6032.
35 * The Algorithmics P-6032's interrupts are wired to GPIO pins
36 * on the BONITO system controller.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: gdium_intr.c,v 1.1 2009/08/06 00:50:26 matt Exp $");
44 #include <sys/param.h>
45 #include <sys/queue.h>
46 #include <sys/malloc.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/kernel.h>
52 #include <machine/bus.h>
53 #include <machine/intr.h>
55 #include <mips/locore.h>
57 #include <mips/bonito/bonitoreg.h>
58 #include <evbmips/gdium/gdiumvar.h>
60 #include <dev/pci/pcireg.h>
61 #include <dev/pci/pcivar.h>
64 * The GDIUM interrupts are wired up in the following way:
69 * GPIN3 BONIDE_INT (in)
72 * GPIN4 ISA IRQ3 (in, also on piix4)
73 * GPIN5 ISA IRQ4 (in, also on piix4)
87 #define IRQ_F_INVERT 0x80 /* invert polarity */
88 #define IRQ_F_EDGE 0x40 /* edge trigger */
89 #define IRQ_F_INT0 0x00 /* INT0 */
90 #define IRQ_F_INT1 0x01 /* INT1 */
91 #define IRQ_F_INT2 0x02 /* INT2 */
92 #define IRQ_F_INT3 0x03 /* INT3 */
93 #define IRQ_F_INTMASK 0x07 /* INT mask */
95 const struct gdium_irqmap gdium_irqmap
[] = {
96 { "gpio0", GDIUM_IRQ_GPIO0
, IRQ_F_INT0
},
97 { "gpio1", GDIUM_IRQ_GPIO1
, IRQ_F_INT0
},
98 { "gpio2", GDIUM_IRQ_GPIO2
, IRQ_F_INT0
},
99 { "gpio3", GDIUM_IRQ_GPIO3
, IRQ_F_INT0
},
101 { "pci inta", GDIUM_IRQ_PCI_INTA
, IRQ_F_INT0
},
102 { "pci intb", GDIUM_IRQ_PCI_INTB
, IRQ_F_INT0
},
103 { "pci intc", GDIUM_IRQ_PCI_INTC
, IRQ_F_INT0
},
104 { "pci intd", GDIUM_IRQ_PCI_INTD
, IRQ_F_INT0
},
106 { "pci perr", GDIUM_IRQ_PCI_PERR
, IRQ_F_EDGE
|IRQ_F_INT1
},
107 { "pci serr", GDIUM_IRQ_PCI_SERR
, IRQ_F_EDGE
|IRQ_F_INT1
},
109 { "denali", GDIUM_IRQ_DENALI
, IRQ_F_INT1
},
111 { "mips int0", GDIUM_IRQ_INT0
, IRQ_F_INT0
},
112 { "mips int1", GDIUM_IRQ_INT1
, IRQ_F_INT1
},
113 { "mips int2", GDIUM_IRQ_INT2
, IRQ_F_INT2
},
114 { "mips int3", GDIUM_IRQ_INT3
, IRQ_F_INT3
},
117 struct gdium_intrhead
{
118 struct evcnt intr_count
;
121 struct gdium_intrhead gdium_intrtab
[__arraycount(gdium_irqmap
)];
123 #define NINTRS 2 /* MIPS INT0 - INT1 */
125 struct gdium_cpuintr
{
126 LIST_HEAD(, evbmips_intrhand
) cintr_list
;
127 struct evcnt cintr_count
;
131 struct gdium_cpuintr gdium_cpuintrs
[NINTRS
];
132 const char *gdium_cpuintrnames
[NINTRS
] = {
138 * This is a mask of bits to clear in the SR when we go to a
139 * given hardware interrupt priority level.
141 const uint32_t ipl_sr_bits
[_IPL_N
] = {
144 MIPS_SOFT_INT_MASK_0
,
145 #if IPL_SOFTCLOCK != IPL_SOFTBIO
147 MIPS_SOFT_INT_MASK_0
,
150 MIPS_SOFT_INT_MASK_0
| MIPS_SOFT_INT_MASK_1
,
151 #if IPL_SOFTNET != IPL_SOFTSERIAL
153 MIPS_SOFT_INT_MASK_0
| MIPS_SOFT_INT_MASK_1
,
156 MIPS_SOFT_INT_MASK_0
| MIPS_SOFT_INT_MASK_1
|
163 MIPS_SOFT_INT_MASK_0
| MIPS_SOFT_INT_MASK_1
|
173 * This is a mask of bits to clear in the SR when we go to a
174 * given software interrupt priority level.
175 * Hardware ipls are port/board specific.
177 const uint32_t mips_ipl_si_to_sr
[] = {
178 [IPL_SOFTCLOCK
-IPL_SOFTCLOCK
] = MIPS_SOFT_INT_MASK_0
,
179 #if IPL_SOFTCLOCK != IPL_SOFTBIO
180 [IPL_SOFTBIO
-IPL_SOFTCLOCK
] = MIPS_SOFT_INT_MASK_0
,
182 [IPL_SOFTNET
-IPL_SOFTCLOCK
] = MIPS_SOFT_INT_MASK_1
,
183 #if IPL_SOFTNET != IPL_SOFTSERIAL
184 [IPL_SOFTSERIAL
-IPL_SOFTCLOCK
] = MIPS_SOFT_INT_MASK_1
,
188 int gdium_pci_intr_map(struct pci_attach_args
*, pci_intr_handle_t
*);
189 const char *gdium_pci_intr_string(void *, pci_intr_handle_t
);
190 const struct evcnt
*gdium_pci_intr_evcnt(void *, pci_intr_handle_t
);
191 void *gdium_pci_intr_establish(void *, pci_intr_handle_t
, int,
192 int (*)(void *), void *);
193 void gdium_pci_intr_disestablish(void *, void *);
194 void gdium_pci_conf_interrupt(void *, int, int, int, int, int *);
197 evbmips_intr_init(void)
199 struct gdium_config
*gc
= &gdium_configuration
;
200 struct bonito_config
*bc
= &gc
->gc_bonito
;
201 const struct gdium_irqmap
*irqmap
;
205 for (i
= 0; i
< NINTRS
; i
++) {
206 LIST_INIT(&gdium_cpuintrs
[i
].cintr_list
);
207 evcnt_attach_dynamic(&gdium_cpuintrs
[i
].cintr_count
,
208 EVCNT_TYPE_INTR
, NULL
, "mips", gdium_cpuintrnames
[i
]);
210 //evcnt_attach_static(&mips_int5_evcnt);
212 for (i
= 0; i
< __arraycount(gdium_irqmap
); i
++) {
213 irqmap
= &gdium_irqmap
[i
];
214 intbit
= 1 << irqmap
->irqidx
;
216 evcnt_attach_dynamic(&gdium_intrtab
[i
].intr_count
,
217 EVCNT_TYPE_INTR
, NULL
, "bonito", irqmap
->name
);
219 if (irqmap
->irqidx
< 4)
220 bc
->bc_gpioIE
|= intbit
;
221 if (irqmap
->flags
& IRQ_F_INVERT
)
222 bc
->bc_intPol
|= intbit
;
223 if (irqmap
->flags
& IRQ_F_EDGE
)
224 bc
->bc_intEdge
|= intbit
;
225 if ((irqmap
->flags
& IRQ_F_INTMASK
) == IRQ_F_INT1
)
226 bc
->bc_intSteer
|= intbit
;
228 REGVAL(BONITO_INTENCLR
) = intbit
;
231 REGVAL(BONITO_GPIOIE
) = bc
->bc_gpioIE
;
232 REGVAL(BONITO_INTEDGE
) = bc
->bc_intEdge
;
233 REGVAL(BONITO_INTSTEER
) = bc
->bc_intSteer
;
234 REGVAL(BONITO_INTPOL
) = bc
->bc_intPol
;
236 gc
->gc_pc
.pc_intr_v
= NULL
;
237 gc
->gc_pc
.pc_intr_map
= gdium_pci_intr_map
;
238 gc
->gc_pc
.pc_intr_string
= gdium_pci_intr_string
;
239 gc
->gc_pc
.pc_intr_evcnt
= gdium_pci_intr_evcnt
;
240 gc
->gc_pc
.pc_intr_establish
= gdium_pci_intr_establish
;
241 gc
->gc_pc
.pc_intr_disestablish
= gdium_pci_intr_disestablish
;
242 gc
->gc_pc
.pc_conf_interrupt
= gdium_pci_conf_interrupt
;
244 /* We let the PCI-ISA bridge code handle this. */
245 gc
->gc_pc
.pc_pciide_compat_intr_establish
= NULL
;
249 evbmips_intr_establish(int irq
, int (*func
)(void *), void *arg
)
251 const struct gdium_irqmap
*irqmap
;
252 struct evbmips_intrhand
*ih
;
256 irqmap
= &gdium_irqmap
[irq
];
257 KASSERT(irq
< __arraycount(gdium_irqmap
));
259 KASSERT(irq
== irqmap
->irqidx
);
261 ih
= malloc(sizeof(*ih
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
272 * First, link it into the tables.
274 level
= (irqmap
->flags
& IRQ_F_INT1
) != 0;
275 LIST_INSERT_HEAD(&gdium_cpuintrs
[level
].cintr_list
, ih
, ih_q
);
276 gdium_cpuintrs
[level
].cintr_refcnt
++;
281 if (gdium_intrtab
[ih
->ih_irq
].intr_refcnt
++ == 0)
282 REGVAL(BONITO_INTENSET
) = (1 << ih
->ih_irq
);
290 evbmips_intr_disestablish(void *cookie
)
292 const struct gdium_irqmap
*irqmap
;
293 struct evbmips_intrhand
*ih
= cookie
;
296 irqmap
= &gdium_irqmap
[ih
->ih_irq
];
301 * First, remove it from the table.
303 LIST_REMOVE(ih
, ih_q
);
304 gdium_cpuintrs
[(irqmap
->flags
& IRQ_F_INT1
) != 0].cintr_refcnt
--;
307 * Now, disable it, if there is nothing remaining on the
310 if (gdium_intrtab
[ih
->ih_irq
].intr_refcnt
-- == 1)
311 REGVAL(BONITO_INTENCLR
) = (1 << ih
->ih_irq
);
319 evbmips_iointr(uint32_t status
, uint32_t cause
, uint32_t pc
,
322 const struct gdium_irqmap
*irqmap
;
323 struct evbmips_intrhand
*ih
;
328 * Read the interrupt pending registers, mask them with the
329 * ones we have enabled, and service them in order of decreasing
332 isr
= REGVAL(BONITO_INTISR
) & REGVAL(BONITO_INTEN
);
333 for (level
= 1; level
>= 0; level
--) {
334 if ((ipending
& (MIPS_INT_MASK_4
<< level
)) == 0)
336 gdium_cpuintrs
[level
].cintr_count
.ev_count
++;
337 LIST_FOREACH (ih
, &gdium_cpuintrs
[level
].cintr_list
, ih_q
) {
338 irqmap
= &gdium_irqmap
[ih
->ih_irq
];
339 if (isr
& (1 << ih
->ih_irq
)) {
340 gdium_intrtab
[ih
->ih_irq
].intr_count
.ev_count
++;
341 (*ih
->ih_func
)(ih
->ih_arg
);
344 cause
&= ~(MIPS_INT_MASK_0
<< level
);
347 /* Re-enable anything that we have processed. */
348 _splset(MIPS_SR_INT_IE
| ((status
& ~cause
) & MIPS_HARD_INT_MASK
));
351 /*****************************************************************************
352 * PCI interrupt support
353 *****************************************************************************/
356 gdium_pci_intr_map(struct pci_attach_args
*pa
,
357 pci_intr_handle_t
*ihp
)
359 static const int8_t pciirqmap
[5/*device*/] = {
360 GDIUM_IRQ_PCI_INTC
, /* 13: PCI 802.11 */
361 GDIUM_IRQ_PCI_INTA
, /* 14: SM501 */
362 GDIUM_IRQ_PCI_INTB
, /* 15: NEC USB (2 func) */
363 GDIUM_IRQ_PCI_INTD
, /* 16: Ethernet */
364 GDIUM_IRQ_PCI_INTC
, /* 17: NEC USB (2 func) */
366 pcitag_t bustag
= pa
->pa_intrtag
;
367 int buspin
= pa
->pa_intrpin
;
368 pci_chipset_tag_t pc
= pa
->pa_pc
;
377 printf("gdium_pci_intr_map: bad interrupt pin %d\n",
382 pci_decompose_tag(pc
, bustag
, NULL
, &device
, NULL
);
383 if (device
< 13 || device
> 17) {
384 printf("gdium_pci_intr_map: bad device %d\n",
389 *ihp
= pciirqmap
[device
- 13];
394 gdium_pci_intr_string(void *v
, pci_intr_handle_t ih
)
397 if (ih
>= __arraycount(gdium_irqmap
))
398 panic("gdium_intr_string: bogus IRQ %ld", ih
);
400 return gdium_irqmap
[ih
].name
;
404 gdium_pci_intr_evcnt(void *v
, pci_intr_handle_t ih
)
407 return &gdium_intrtab
[ih
].intr_count
;
411 gdium_pci_intr_establish(void *v
, pci_intr_handle_t ih
, int level
,
412 int (*func
)(void *), void *arg
)
415 if (ih
>= __arraycount(gdium_irqmap
))
416 panic("gdium_pci_intr_establish: bogus IRQ %ld", ih
);
418 return evbmips_intr_establish(ih
, func
, arg
);
422 gdium_pci_intr_disestablish(void *v
, void *cookie
)
425 return (evbmips_intr_disestablish(cookie
));
429 gdium_pci_conf_interrupt(void *v
, int bus
, int dev
, int pin
, int swiz
,
434 * We actually don't need to do anything; everything is handled