4 * NetBSD: omap2_icu.c,v 1.4 2008/08/27 11:03:10 matt Exp
8 * Define the SDP2430 specific information and then include the generic OMAP
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain this list of conditions
17 * and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce this list of conditions
19 * and the following disclaimer in the documentation and/or other materials
20 * provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "opt_gemini.h"
34 #include "geminiicu.h"
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: gemini_icu.c,v 1.2 2008/10/24 17:46:59 matt Exp $");
41 #include <sys/param.h>
42 #include <sys/evcnt.h>
44 #include <uvm/uvm_extern.h>
46 #include <machine/intr.h>
47 #include <machine/bus.h>
50 #include <arm/armreg.h>
51 #include <arm/cpufunc.h>
52 #include <arm/atomic.h>
54 #include <arm/pic/picvar.h>
56 #include <arm/gemini/gemini_reg.h>
57 #include <arm/gemini/gemini_obiovar.h>
60 #define INTC_READ(sc, o) \
61 bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (o))
62 #define INTC_WRITE(sc, o, v) \
63 bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (o), v)
65 static int geminiicu_match(device_t
, cfdata_t
, void *);
66 static void geminiicu_attach(device_t
, device_t
, void *);
68 static void geminiicu_unblock_irqs(struct pic_softc
*, size_t, uint32_t);
69 static void geminiicu_block_irqs(struct pic_softc
*, size_t, uint32_t);
70 static void geminiicu_establish_irq(struct pic_softc
*, struct intrsource
*);
71 static void geminiicu_source_name(struct pic_softc
*, int, char *, size_t);
73 static const struct pic_ops geminiicu_picops
= {
74 .pic_unblock_irqs
= geminiicu_unblock_irqs
,
75 .pic_block_irqs
= geminiicu_block_irqs
,
76 .pic_establish_irq
= geminiicu_establish_irq
,
77 .pic_source_name
= geminiicu_source_name
,
80 #define PICTOSOFTC(pic) \
81 ((void *)((uintptr_t)(pic) - offsetof(struct geminiicu_softc, sc_pic)))
83 static struct geminiicu_softc
{
85 bus_space_tag_t sc_memt
;
86 bus_space_handle_t sc_memh
;
87 struct pic_softc sc_pic
;
88 uint32_t sc_enabled_mask
;
89 uint32_t sc_edge_mask
;
90 uint32_t sc_edge_rising_mask
;
91 uint32_t sc_edge_falling_mask
;
92 uint32_t sc_level_mask
;
93 uint32_t sc_level_hi_mask
;
94 uint32_t sc_level_lo_mask
;
97 .pic_ops
= &geminiicu_picops
,
99 .pic_name
= "geminiicu",
103 static const char * const sources
[32] = {
104 "ipi(0)", "gmac0(1)", "gmac1(2)", "wdt(3)",
105 "ide0(4)", "ide1(5)", "raid(6)", "crypto(7)",
106 "pci(8)", "dma(9)", "usb0(10)", "usb1(11)",
107 "flash(12)", "tve(13)", "timer0(14)", "timer1(15)",
108 "timer2(16)", "rtc(17)", "uart(18)", "lcd(19)",
109 "lpc(20)", "ssp(21)", "gpio0(22)", "gpio1(23)",
110 "gpio2(24)", "cir(25)", "power(26)", "irq 27",
111 "irq 28", "irq 29", "usbc0(30)", "usbc1(31)"
114 static void geminiicu_source_name(struct pic_softc
*pic
, int irq
,
115 char *buf
, size_t len
)
117 KASSERT((unsigned int)irq
< 32);
118 strlcpy(buf
, sources
[irq
], len
);
122 geminiicu_unblock_irqs(struct pic_softc
*pic
, size_t irqbase
, uint32_t irq_mask
)
124 struct geminiicu_softc
* const sc
= PICTOSOFTC(pic
);
125 KASSERT(irqbase
== 0 && (irq_mask
& sc
->sc_enabled_mask
) == 0);
126 sc
->sc_enabled_mask
|= irq_mask
;
127 INTC_WRITE(sc
, GEMINI_ICU_IRQ_ENABLE
, sc
->sc_enabled_mask
);
129 * If this is a level source, ack it now. If it's still asserted
132 if (irq_mask
& sc
->sc_level_mask
)
133 INTC_WRITE(sc
, GEMINI_ICU_IRQ_CLEAR
,
134 irq_mask
& sc
->sc_level_mask
);
138 geminiicu_block_irqs(struct pic_softc
*pic
, size_t irqbase
, uint32_t irq_mask
)
140 struct geminiicu_softc
* const sc
= PICTOSOFTC(pic
);
141 KASSERT(irqbase
== 0);
143 sc
->sc_enabled_mask
&= ~irq_mask
;
144 INTC_WRITE(sc
, GEMINI_ICU_IRQ_ENABLE
, sc
->sc_enabled_mask
);
146 * If any of the source are edge triggered, ack them now so
147 * we won't lose them.
149 if (irq_mask
& sc
->sc_edge_mask
)
150 INTC_WRITE(sc
, GEMINI_ICU_IRQ_CLEAR
,
151 irq_mask
& sc
->sc_edge_mask
);
155 * Called with interrupts disabled
158 find_pending_irqs(struct geminiicu_softc
*sc
)
160 uint32_t pending
= INTC_READ(sc
, GEMINI_ICU_IRQ_STATUS
);
162 KASSERT((sc
->sc_enabled_mask
& pending
) == pending
);
167 return pic_mark_pending_sources(&sc
->sc_pic
, 0, pending
);
171 gemini_irq_handler(void *frame
)
173 struct cpu_info
* const ci
= curcpu();
174 struct geminiicu_softc
* const sc
= &geminiicu_softc
;
175 const int oldipl
= ci
->ci_cpl
;
176 const uint32_t oldipl_mask
= __BIT(oldipl
);
181 KASSERT(sc
->sc_enabled_mask
!= 0);
183 ipl_mask
= find_pending_irqs(sc
);
186 * Record the pending_ipls and deliver them if we can.
188 if ((ipl_mask
& ~oldipl_mask
) > oldipl_mask
)
189 pic_do_pending_ints(I32_bit
, oldipl
, frame
);
193 geminiicu_establish_irq(struct pic_softc
*pic
, struct intrsource
*is
)
195 struct geminiicu_softc
* const sc
= PICTOSOFTC(pic
);
196 const uint32_t irq_mask
= __BIT(is
->is_irq
);
198 KASSERT(is
->is_irq
< 32);
200 sc
->sc_enabled_mask
&= ~irq_mask
;
201 /* Have to do with this interrupt disabled. */
202 INTC_WRITE(sc
, GEMINI_ICU_IRQ_ENABLE
, sc
->sc_enabled_mask
);
203 INTC_WRITE(sc
, GEMINI_ICU_IRQ_CLEAR
, irq_mask
);
205 sc
->sc_edge_rising_mask
&= ~irq_mask
;
206 sc
->sc_edge_falling_mask
&= ~irq_mask
;
207 sc
->sc_level_lo_mask
&= ~irq_mask
;
208 sc
->sc_level_hi_mask
&= ~irq_mask
;
210 switch (is
->is_type
) {
211 case IST_LEVEL_LOW
: sc
->sc_level_lo_mask
|= irq_mask
; break;
212 case IST_LEVEL_HIGH
: sc
->sc_level_hi_mask
|= irq_mask
; break;
213 case IST_EDGE_FALLING
: sc
->sc_edge_falling_mask
|= irq_mask
; break;
214 case IST_EDGE_RISING
: sc
->sc_edge_rising_mask
|= irq_mask
; break;
217 sc
->sc_edge_mask
= sc
->sc_edge_rising_mask
| sc
->sc_edge_falling_mask
;
218 sc
->sc_level_mask
= sc
->sc_level_hi_mask
|sc
->sc_level_lo_mask
;
221 * Set the new interrupt mode.
223 INTC_WRITE(sc
, GEMINI_ICU_IRQ_TRIGMODE
, sc
->sc_edge_mask
);
224 INTC_WRITE(sc
, GEMINI_ICU_IRQ_TRIGLEVEL
,
225 sc
->sc_level_lo_mask
| sc
->sc_edge_falling_mask
);
229 geminiicu_match(device_t parent
, cfdata_t cf
, void *aux
)
231 struct obio_attach_args
* const oa
= aux
;
234 if ((oa
->obio_addr
== GEMINI_IC0_BASE
)
235 || (oa
->obio_addr
== GEMINI_IC1_BASE
))
240 #error unsupported GEMINI variant
245 geminiicu_attach(device_t parent
, device_t self
, void *aux
)
247 struct obio_attach_args
* const oa
= aux
;
248 struct geminiicu_softc
* const sc
= &geminiicu_softc
;
253 sc
->sc_memt
= oa
->obio_iot
;
255 error
= bus_space_map(sc
->sc_memt
, oa
->obio_addr
, 0x1000, 0,
258 panic("failed to map interrupt registers: %d", error
);
260 INTC_WRITE(sc
, GEMINI_ICU_IRQ_ENABLE
, 0);
261 INTC_WRITE(sc
, GEMINI_ICU_IRQ_CLEAR
, 0xffffffff);
262 INTC_WRITE(sc
, GEMINI_ICU_IRQ_TRIGMODE
, 0);
263 INTC_WRITE(sc
, GEMINI_ICU_IRQ_TRIGLEVEL
, 0xffffffff);
266 self
->dv_private
= sc
;
268 pic_add(&sc
->sc_pic
, 0);
271 CFATTACH_DECL_NEW(geminiicu
,
273 geminiicu_match
, geminiicu_attach
,