gemini_icu.c revision 1.2.8.2 1 1.2.8.2 mjf /* $NetBSD */
2 1.2.8.2 mjf
3 1.2.8.2 mjf /* adapted from:
4 1.2.8.2 mjf * NetBSD: omap2_icu.c,v 1.4 2008/08/27 11:03:10 matt Exp
5 1.2.8.2 mjf */
6 1.2.8.2 mjf
7 1.2.8.2 mjf /*
8 1.2.8.2 mjf * Define the SDP2430 specific information and then include the generic OMAP
9 1.2.8.2 mjf * interrupt header.
10 1.2.8.2 mjf */
11 1.2.8.2 mjf
12 1.2.8.2 mjf /*
13 1.2.8.2 mjf * Redistribution and use in source and binary forms, with or without
14 1.2.8.2 mjf * modification, are permitted provided that the following conditions
15 1.2.8.2 mjf * are met:
16 1.2.8.2 mjf * 1. Redistributions of source code must retain this list of conditions
17 1.2.8.2 mjf * and the following disclaimer.
18 1.2.8.2 mjf * 2. Redistributions in binary form must reproduce this list of conditions
19 1.2.8.2 mjf * and the following disclaimer in the documentation and/or other materials
20 1.2.8.2 mjf * provided with the distribution.
21 1.2.8.2 mjf *
22 1.2.8.2 mjf * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 1.2.8.2 mjf * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24 1.2.8.2 mjf * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
25 1.2.8.2 mjf * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 1.2.8.2 mjf * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 1.2.8.2 mjf * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 1.2.8.2 mjf * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 1.2.8.2 mjf * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 1.2.8.2 mjf * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 1.2.8.2 mjf * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.2.8.2 mjf */
33 1.2.8.2 mjf #include "opt_gemini.h"
34 1.2.8.2 mjf #include "geminiicu.h"
35 1.2.8.2 mjf
36 1.2.8.2 mjf #define _INTR_PRIVATE
37 1.2.8.2 mjf
38 1.2.8.2 mjf #include <sys/cdefs.h>
39 1.2.8.2 mjf __KERNEL_RCSID(0, "$NetBSD: gemini_icu.c,v 1.2.8.2 2009/01/17 13:27:52 mjf Exp $");
40 1.2.8.2 mjf
41 1.2.8.2 mjf #include <sys/param.h>
42 1.2.8.2 mjf #include <sys/evcnt.h>
43 1.2.8.2 mjf
44 1.2.8.2 mjf #include <uvm/uvm_extern.h>
45 1.2.8.2 mjf
46 1.2.8.2 mjf #include <machine/intr.h>
47 1.2.8.2 mjf #include <machine/bus.h>
48 1.2.8.2 mjf
49 1.2.8.2 mjf #include <arm/cpu.h>
50 1.2.8.2 mjf #include <arm/armreg.h>
51 1.2.8.2 mjf #include <arm/cpufunc.h>
52 1.2.8.2 mjf #include <arm/atomic.h>
53 1.2.8.2 mjf
54 1.2.8.2 mjf #include <arm/pic/picvar.h>
55 1.2.8.2 mjf
56 1.2.8.2 mjf #include <arm/gemini/gemini_reg.h>
57 1.2.8.2 mjf #include <arm/gemini/gemini_obiovar.h>
58 1.2.8.2 mjf
59 1.2.8.2 mjf
60 1.2.8.2 mjf #define INTC_READ(sc, o) \
61 1.2.8.2 mjf bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (o))
62 1.2.8.2 mjf #define INTC_WRITE(sc, o, v) \
63 1.2.8.2 mjf bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (o), v)
64 1.2.8.2 mjf
65 1.2.8.2 mjf static int geminiicu_match(device_t, cfdata_t, void *);
66 1.2.8.2 mjf static void geminiicu_attach(device_t, device_t, void *);
67 1.2.8.2 mjf
68 1.2.8.2 mjf static void geminiicu_unblock_irqs(struct pic_softc *, size_t, uint32_t);
69 1.2.8.2 mjf static void geminiicu_block_irqs(struct pic_softc *, size_t, uint32_t);
70 1.2.8.2 mjf static void geminiicu_establish_irq(struct pic_softc *, struct intrsource *);
71 1.2.8.2 mjf static void geminiicu_source_name(struct pic_softc *, int, char *, size_t);
72 1.2.8.2 mjf
73 1.2.8.2 mjf static const struct pic_ops geminiicu_picops = {
74 1.2.8.2 mjf .pic_unblock_irqs = geminiicu_unblock_irqs,
75 1.2.8.2 mjf .pic_block_irqs = geminiicu_block_irqs,
76 1.2.8.2 mjf .pic_establish_irq = geminiicu_establish_irq,
77 1.2.8.2 mjf .pic_source_name = geminiicu_source_name,
78 1.2.8.2 mjf };
79 1.2.8.2 mjf
80 1.2.8.2 mjf #define PICTOSOFTC(pic) \
81 1.2.8.2 mjf ((void *)((uintptr_t)(pic) - offsetof(struct geminiicu_softc, sc_pic)))
82 1.2.8.2 mjf
83 1.2.8.2 mjf static struct geminiicu_softc {
84 1.2.8.2 mjf device_t sc_dev;
85 1.2.8.2 mjf bus_space_tag_t sc_memt;
86 1.2.8.2 mjf bus_space_handle_t sc_memh;
87 1.2.8.2 mjf struct pic_softc sc_pic;
88 1.2.8.2 mjf uint32_t sc_enabled_mask;
89 1.2.8.2 mjf uint32_t sc_edge_mask;
90 1.2.8.2 mjf uint32_t sc_edge_rising_mask;
91 1.2.8.2 mjf uint32_t sc_edge_falling_mask;
92 1.2.8.2 mjf uint32_t sc_level_mask;
93 1.2.8.2 mjf uint32_t sc_level_hi_mask;
94 1.2.8.2 mjf uint32_t sc_level_lo_mask;
95 1.2.8.2 mjf } geminiicu_softc = {
96 1.2.8.2 mjf .sc_pic = {
97 1.2.8.2 mjf .pic_ops = &geminiicu_picops,
98 1.2.8.2 mjf .pic_maxsources = 32,
99 1.2.8.2 mjf .pic_name = "geminiicu",
100 1.2.8.2 mjf },
101 1.2.8.2 mjf };
102 1.2.8.2 mjf
103 1.2.8.2 mjf static const char * const sources[32] = {
104 1.2.8.2 mjf "ipi(0)", "gmac0(1)", "gmac1(2)", "wdt(3)",
105 1.2.8.2 mjf "ide0(4)", "ide1(5)", "raid(6)", "crypto(7)",
106 1.2.8.2 mjf "pci(8)", "dma(9)", "usb0(10)", "usb1(11)",
107 1.2.8.2 mjf "flash(12)", "tve(13)", "timer0(14)", "timer1(15)",
108 1.2.8.2 mjf "timer2(16)", "rtc(17)", "uart(18)", "lcd(19)",
109 1.2.8.2 mjf "lpc(20)", "ssp(21)", "gpio0(22)", "gpio1(23)",
110 1.2.8.2 mjf "gpio2(24)", "cir(25)", "power(26)", "irq 27",
111 1.2.8.2 mjf "irq 28", "irq 29", "usbc0(30)", "usbc1(31)"
112 1.2.8.2 mjf };
113 1.2.8.2 mjf
114 1.2.8.2 mjf static void geminiicu_source_name(struct pic_softc *pic, int irq,
115 1.2.8.2 mjf char *buf, size_t len)
116 1.2.8.2 mjf {
117 1.2.8.2 mjf KASSERT((unsigned int)irq < 32);
118 1.2.8.2 mjf strlcpy(buf, sources[irq], len);
119 1.2.8.2 mjf }
120 1.2.8.2 mjf
121 1.2.8.2 mjf static void
122 1.2.8.2 mjf geminiicu_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
123 1.2.8.2 mjf {
124 1.2.8.2 mjf struct geminiicu_softc * const sc = PICTOSOFTC(pic);
125 1.2.8.2 mjf KASSERT(irqbase == 0 && (irq_mask & sc->sc_enabled_mask) == 0);
126 1.2.8.2 mjf sc->sc_enabled_mask |= irq_mask;
127 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
128 1.2.8.2 mjf /*
129 1.2.8.2 mjf * If this is a level source, ack it now. If it's still asserted
130 1.2.8.2 mjf * it'll come back.
131 1.2.8.2 mjf */
132 1.2.8.2 mjf if (irq_mask & sc->sc_level_mask)
133 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR,
134 1.2.8.2 mjf irq_mask & sc->sc_level_mask);
135 1.2.8.2 mjf }
136 1.2.8.2 mjf
137 1.2.8.2 mjf static void
138 1.2.8.2 mjf geminiicu_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
139 1.2.8.2 mjf {
140 1.2.8.2 mjf struct geminiicu_softc * const sc = PICTOSOFTC(pic);
141 1.2.8.2 mjf KASSERT(irqbase == 0);
142 1.2.8.2 mjf
143 1.2.8.2 mjf sc->sc_enabled_mask &= ~irq_mask;
144 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
145 1.2.8.2 mjf /*
146 1.2.8.2 mjf * If any of the source are edge triggered, ack them now so
147 1.2.8.2 mjf * we won't lose them.
148 1.2.8.2 mjf */
149 1.2.8.2 mjf if (irq_mask & sc->sc_edge_mask)
150 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR,
151 1.2.8.2 mjf irq_mask & sc->sc_edge_mask);
152 1.2.8.2 mjf }
153 1.2.8.2 mjf
154 1.2.8.2 mjf /*
155 1.2.8.2 mjf * Called with interrupts disabled
156 1.2.8.2 mjf */
157 1.2.8.2 mjf static int
158 1.2.8.2 mjf find_pending_irqs(struct geminiicu_softc *sc)
159 1.2.8.2 mjf {
160 1.2.8.2 mjf uint32_t pending = INTC_READ(sc, GEMINI_ICU_IRQ_STATUS);
161 1.2.8.2 mjf
162 1.2.8.2 mjf KASSERT((sc->sc_enabled_mask & pending) == pending);
163 1.2.8.2 mjf
164 1.2.8.2 mjf if (pending == 0)
165 1.2.8.2 mjf return 0;
166 1.2.8.2 mjf
167 1.2.8.2 mjf return pic_mark_pending_sources(&sc->sc_pic, 0, pending);
168 1.2.8.2 mjf }
169 1.2.8.2 mjf
170 1.2.8.2 mjf void
171 1.2.8.2 mjf gemini_irq_handler(void *frame)
172 1.2.8.2 mjf {
173 1.2.8.2 mjf struct cpu_info * const ci = curcpu();
174 1.2.8.2 mjf struct geminiicu_softc * const sc = &geminiicu_softc;
175 1.2.8.2 mjf const int oldipl = ci->ci_cpl;
176 1.2.8.2 mjf const uint32_t oldipl_mask = __BIT(oldipl);
177 1.2.8.2 mjf int ipl_mask = 0;
178 1.2.8.2 mjf
179 1.2.8.2 mjf uvmexp.intrs++;
180 1.2.8.2 mjf
181 1.2.8.2 mjf KASSERT(sc->sc_enabled_mask != 0);
182 1.2.8.2 mjf
183 1.2.8.2 mjf ipl_mask = find_pending_irqs(sc);
184 1.2.8.2 mjf
185 1.2.8.2 mjf /*
186 1.2.8.2 mjf * Record the pending_ipls and deliver them if we can.
187 1.2.8.2 mjf */
188 1.2.8.2 mjf if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
189 1.2.8.2 mjf pic_do_pending_ints(I32_bit, oldipl, frame);
190 1.2.8.2 mjf }
191 1.2.8.2 mjf
192 1.2.8.2 mjf void
193 1.2.8.2 mjf geminiicu_establish_irq(struct pic_softc *pic, struct intrsource *is)
194 1.2.8.2 mjf {
195 1.2.8.2 mjf struct geminiicu_softc * const sc = PICTOSOFTC(pic);
196 1.2.8.2 mjf const uint32_t irq_mask = __BIT(is->is_irq);
197 1.2.8.2 mjf
198 1.2.8.2 mjf KASSERT(is->is_irq < 32);
199 1.2.8.2 mjf
200 1.2.8.2 mjf sc->sc_enabled_mask &= ~irq_mask;
201 1.2.8.2 mjf /* Have to do with this interrupt disabled. */
202 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
203 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR, irq_mask);
204 1.2.8.2 mjf
205 1.2.8.2 mjf sc->sc_edge_rising_mask &= ~irq_mask;
206 1.2.8.2 mjf sc->sc_edge_falling_mask &= ~irq_mask;
207 1.2.8.2 mjf sc->sc_level_lo_mask &= ~irq_mask;
208 1.2.8.2 mjf sc->sc_level_hi_mask &= ~irq_mask;
209 1.2.8.2 mjf
210 1.2.8.2 mjf switch (is->is_type) {
211 1.2.8.2 mjf case IST_LEVEL_LOW: sc->sc_level_lo_mask |= irq_mask; break;
212 1.2.8.2 mjf case IST_LEVEL_HIGH: sc->sc_level_hi_mask |= irq_mask; break;
213 1.2.8.2 mjf case IST_EDGE_FALLING: sc->sc_edge_falling_mask |= irq_mask; break;
214 1.2.8.2 mjf case IST_EDGE_RISING: sc->sc_edge_rising_mask |= irq_mask; break;
215 1.2.8.2 mjf }
216 1.2.8.2 mjf
217 1.2.8.2 mjf sc->sc_edge_mask = sc->sc_edge_rising_mask | sc->sc_edge_falling_mask;
218 1.2.8.2 mjf sc->sc_level_mask = sc->sc_level_hi_mask|sc->sc_level_lo_mask;
219 1.2.8.2 mjf
220 1.2.8.2 mjf /*
221 1.2.8.2 mjf * Set the new interrupt mode.
222 1.2.8.2 mjf */
223 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGMODE, sc->sc_edge_mask);
224 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGLEVEL,
225 1.2.8.2 mjf sc->sc_level_lo_mask | sc->sc_edge_falling_mask);
226 1.2.8.2 mjf }
227 1.2.8.2 mjf
228 1.2.8.2 mjf int
229 1.2.8.2 mjf geminiicu_match(device_t parent, cfdata_t cf, void *aux)
230 1.2.8.2 mjf {
231 1.2.8.2 mjf struct obio_attach_args * const oa = aux;
232 1.2.8.2 mjf
233 1.2.8.2 mjf #if defined(SL3516)
234 1.2.8.2 mjf if ((oa->obio_addr == GEMINI_IC0_BASE)
235 1.2.8.2 mjf || (oa->obio_addr == GEMINI_IC1_BASE))
236 1.2.8.2 mjf return 1;
237 1.2.8.2 mjf
238 1.2.8.2 mjf return 0;
239 1.2.8.2 mjf #else
240 1.2.8.2 mjf #error unsupported GEMINI variant
241 1.2.8.2 mjf #endif
242 1.2.8.2 mjf }
243 1.2.8.2 mjf
244 1.2.8.2 mjf void
245 1.2.8.2 mjf geminiicu_attach(device_t parent, device_t self, void *aux)
246 1.2.8.2 mjf {
247 1.2.8.2 mjf struct obio_attach_args * const oa = aux;
248 1.2.8.2 mjf struct geminiicu_softc * const sc = &geminiicu_softc;
249 1.2.8.2 mjf int error;
250 1.2.8.2 mjf
251 1.2.8.2 mjf aprint_normal("\n");
252 1.2.8.2 mjf
253 1.2.8.2 mjf sc->sc_memt = oa->obio_iot;
254 1.2.8.2 mjf
255 1.2.8.2 mjf error = bus_space_map(sc->sc_memt, oa->obio_addr, 0x1000, 0,
256 1.2.8.2 mjf &sc->sc_memh);
257 1.2.8.2 mjf if (error)
258 1.2.8.2 mjf panic("failed to map interrupt registers: %d", error);
259 1.2.8.2 mjf
260 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, 0);
261 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR, 0xffffffff);
262 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGMODE, 0);
263 1.2.8.2 mjf INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGLEVEL, 0xffffffff);
264 1.2.8.2 mjf
265 1.2.8.2 mjf sc->sc_dev = self;
266 1.2.8.2 mjf self->dv_private = sc;
267 1.2.8.2 mjf
268 1.2.8.2 mjf pic_add(&sc->sc_pic, 0);
269 1.2.8.2 mjf }
270 1.2.8.2 mjf
271 1.2.8.2 mjf CFATTACH_DECL_NEW(geminiicu,
272 1.2.8.2 mjf 0,
273 1.2.8.2 mjf geminiicu_match, geminiicu_attach,
274 1.2.8.2 mjf NULL, NULL);
275