bcm2835_intr.c revision 1.11 1 /* $NetBSD: bcm2835_intr.c,v 1.11 2015/08/01 14:18:00 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nick Hudson
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.11 2015/08/01 14:18:00 skrll Exp $");
34
35 #define _INTR_PRIVATE
36
37 #include "opt_bcm283x.h"
38
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/cpu.h>
42 #include <sys/device.h>
43 #include <sys/proc.h>
44
45 #include <machine/intr.h>
46
47 #include <arm/locore.h>
48
49 #include <arm/pic/picvar.h>
50 #include <arm/cortex/gtmr_var.h>
51
52 #include <arm/broadcom/bcm_amba.h>
53 #include <arm/broadcom/bcm2835reg.h>
54 #include <arm/broadcom/bcm2835var.h>
55
56 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
57 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
58 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
59 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
60 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
61 size_t);
62
63 #if defined(BCM2836)
64 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
65 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
66 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
67 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
68 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
69 size_t);
70 #ifdef MULTIPROCESSOR
71 int bcm2836mp_ipi_handler(void *);
72 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
73 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
74 #endif
75 #endif
76
77 static int bcm2835_icu_match(device_t, cfdata_t, void *);
78 static void bcm2835_icu_attach(device_t, device_t, void *);
79
80 static struct pic_ops bcm2835_picops = {
81 .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
82 .pic_block_irqs = bcm2835_pic_block_irqs,
83 .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
84 .pic_establish_irq = bcm2835_pic_establish_irq,
85 .pic_source_name = bcm2835_pic_source_name,
86 };
87
88 struct pic_softc bcm2835_pic = {
89 .pic_ops = &bcm2835_picops,
90 .pic_maxsources = BCM2835_NIRQ,
91 .pic_name = "bcm2835 pic",
92 };
93
94 #if defined(BCM2836)
95 static struct pic_ops bcm2836mp_picops = {
96 .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
97 .pic_block_irqs = bcm2836mp_pic_block_irqs,
98 .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
99 .pic_establish_irq = bcm2836mp_pic_establish_irq,
100 .pic_source_name = bcm2836mp_pic_source_name,
101 #if defined(MULTIPROCESSOR)
102 .pic_cpu_init = bcm2836mp_cpu_init,
103 .pic_ipi_send = bcm2836mp_send_ipi,
104 #endif
105 };
106
107 struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
108 [0] = {
109 .pic_ops = &bcm2836mp_picops,
110 .pic_maxsources = BCM2836_NIRQPERCPU,
111 .pic_name = "bcm2836 pic",
112 },
113 [1] = {
114 .pic_ops = &bcm2836mp_picops,
115 .pic_maxsources = BCM2836_NIRQPERCPU,
116 .pic_name = "bcm2836 pic",
117 },
118 [2] = {
119 .pic_ops = &bcm2836mp_picops,
120 .pic_maxsources = BCM2836_NIRQPERCPU,
121 .pic_name = "bcm2836 pic",
122 },
123 [3] = {
124 .pic_ops = &bcm2836mp_picops,
125 .pic_maxsources = BCM2836_NIRQPERCPU,
126 .pic_name = "bcm2836 pic",
127 },
128 };
129 #endif
130
131 struct bcm2835icu_softc {
132 device_t sc_dev;
133 bus_space_tag_t sc_iot;
134 bus_space_handle_t sc_ioh;
135 struct pic_softc *sc_pic;
136 };
137
138 struct bcm2835icu_softc *bcmicu_sc;
139
140 #define read_bcm2835reg(o) \
141 bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
142
143 #define write_bcm2835reg(o, v) \
144 bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
145
146
147 #define bcm2835_barrier() \
148 bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
149 BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
150
151 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
152 "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
153 "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
154 "(unused 8)", "usb", "(unused 10)", "(unused 11)",
155 "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
156 "dma0", "dma1", "dma2", "dma3",
157 "dma4", "dma5", "dma6", "dma7",
158 "dma8", "dma9", "dma10", "dma11",
159 "dma12", "aux", "(unused 30)", "(unused 31)",
160 "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
161 "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
162 "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
163 "(unused 44)", "pwa0", "pwa1", "(unused 47)",
164 "smi", "gpio[0]", "gpio[1]", "gpio[2]",
165 "gpio[3]", "i2c", "spi", "pcm",
166 "sdio", "uart", "(unused 58)", "(unused 59)",
167 "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
168 "Timer", "Mailbox", "Doorbell0", "Doorbell1",
169 "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
170 };
171
172 #if defined(BCM2836)
173 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
174 "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
175 "mailbox0", "mailbox1", "mailbox2", "mailbox3",
176 };
177 #endif
178
179 #define BCM2836_INTBIT_GPUPENDING __BIT(8)
180
181 #define BCM2835_INTBIT_PENDING1 __BIT(8)
182 #define BCM2835_INTBIT_PENDING2 __BIT(9)
183 #define BCM2835_INTBIT_ARM __BITS(0,7)
184 #define BCM2835_INTBIT_GPU0 __BITS(10,14)
185 #define BCM2835_INTBIT_GPU1 __BITS(15,20)
186
187 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
188 bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
189
190 static int
191 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
192 {
193 struct amba_attach_args *aaa = aux;
194
195 if (strcmp(aaa->aaa_name, "icu") != 0)
196 return 0;
197
198 return 1;
199 }
200
201 static void
202 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
203 {
204 struct bcm2835icu_softc *sc = device_private(self);
205 struct amba_attach_args *aaa = aux;
206
207 sc->sc_dev = self;
208 sc->sc_iot = aaa->aaa_iot;
209 sc->sc_pic = &bcm2835_pic;
210
211 if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
212 &sc->sc_ioh)) {
213 aprint_error_dev(self, "unable to map device\n");
214 return;
215 }
216
217 bcmicu_sc = sc;
218
219 #if defined(BCM2836)
220 #if defined(MULTIPROCESSOR)
221 aprint_normal(": Multiprocessor");
222 #endif
223
224 bcm2836mp_intr_init(curcpu());
225 #endif
226 pic_add(sc->sc_pic, BCM2835_INT_BASE);
227
228 aprint_normal("\n");
229 }
230
231 void
232 bcm2835_irq_handler(void *frame)
233 {
234 struct cpu_info * const ci = curcpu();
235 const int oldipl = ci->ci_cpl;
236 const cpuid_t cpuid = ci->ci_cpuid;
237 const uint32_t oldipl_mask = __BIT(oldipl);
238 int ipl_mask = 0;
239
240 ci->ci_data.cpu_nintr++;
241
242 bcm2835_barrier();
243 if (cpuid == 0) {
244 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
245 }
246 #if defined(BCM2836)
247 ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
248 #endif
249
250 /*
251 * Record the pending_ipls and deliver them if we can.
252 */
253 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
254 pic_do_pending_ints(I32_bit, oldipl, frame);
255 }
256
257 static void
258 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
259 uint32_t irq_mask)
260 {
261
262 write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
263 bcm2835_barrier();
264 }
265
266 static void
267 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
268 uint32_t irq_mask)
269 {
270
271 write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
272 bcm2835_barrier();
273 }
274
275 /*
276 * Called with interrupts disabled
277 */
278 static int
279 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
280 {
281 int ipl = 0;
282 uint32_t bpending, gpu0irq, gpu1irq, armirq;
283
284 bcm2835_barrier();
285 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
286 if (bpending == 0)
287 return 0;
288
289 armirq = bpending & BCM2835_INTBIT_ARM;
290 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
291 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
292
293 if (armirq) {
294 ipl |= pic_mark_pending_sources(pic,
295 BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
296
297 }
298
299 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
300 uint32_t pending1;
301
302 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
303 ipl |= pic_mark_pending_sources(pic,
304 BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
305 }
306 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
307 uint32_t pending2;
308
309 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
310 ipl |= pic_mark_pending_sources(pic,
311 BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
312 }
313
314 return ipl;
315 }
316
317 static void
318 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
319 {
320
321 /* Nothing really*/
322 KASSERT(is->is_irq < BCM2835_NIRQ);
323 KASSERT(is->is_type == IST_LEVEL);
324 }
325
326 static void
327 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
328 {
329
330 strlcpy(buf, bcm2835_sources[irq], len);
331 }
332
333
334 #if defined(BCM2836)
335
336 #define BCM2836MP_TIMER_IRQS __BITS(3,0)
337 #define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
338
339 #define BCM2836MP_ALL_IRQS \
340 (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
341
342 static void
343 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
344 uint32_t irq_mask)
345 {
346 struct cpu_info * const ci = curcpu();
347 const cpuid_t cpuid = ci->ci_cpuid;
348
349 KASSERT(pic == &bcm2836mp_pic[cpuid]);
350 KASSERT(irqbase == 0);
351
352 if (irq_mask & BCM2836MP_TIMER_IRQS) {
353 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
354 uint32_t val = bus_space_read_4(al_iot, al_ioh,
355 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
356 val |= mask;
357 bus_space_write_4(al_iot, al_ioh,
358 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
359 val);
360 bus_space_barrier(al_iot, al_ioh,
361 BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
362 BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
363 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
364 }
365 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
366 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
367 uint32_t val = bus_space_read_4(al_iot, al_ioh,
368 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
369 val |= mask;
370 bus_space_write_4(al_iot, al_ioh,
371 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
372 val);
373 bus_space_barrier(al_iot, al_ioh,
374 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
375 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
376 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
377 }
378
379 return;
380 }
381
382 static void
383 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
384 uint32_t irq_mask)
385 {
386 struct cpu_info * const ci = curcpu();
387 const cpuid_t cpuid = ci->ci_cpuid;
388
389 KASSERT(pic == &bcm2836mp_pic[cpuid]);
390 KASSERT(irqbase == 0);
391
392 if (irq_mask & BCM2836MP_TIMER_IRQS) {
393 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
394 uint32_t val = bus_space_read_4(al_iot, al_ioh,
395 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
396 val &= ~mask;
397 bus_space_write_4(al_iot, al_ioh,
398 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
399 val);
400 }
401 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
402 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
403 uint32_t val = bus_space_read_4(al_iot, al_ioh,
404 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
405 val &= ~mask;
406 bus_space_write_4(al_iot, al_ioh,
407 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
408 val);
409 }
410
411 bcm2835_barrier();
412 return;
413 }
414
415 static int
416 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
417 {
418 struct cpu_info * const ci = curcpu();
419 const cpuid_t cpuid = ci->ci_cpuid;
420 uint32_t lpending;
421 int ipl = 0;
422
423 KASSERT(pic == &bcm2836mp_pic[cpuid]);
424
425 bcm2835_barrier();
426
427 lpending = bus_space_read_4(al_iot, al_ioh,
428 BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
429
430 lpending &= ~BCM2836_INTBIT_GPUPENDING;
431 if (lpending & BCM2836MP_ALL_IRQS) {
432 ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
433 lpending & BCM2836MP_ALL_IRQS);
434 }
435
436 return ipl;
437 }
438
439 static void
440 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
441 {
442 /* Nothing really*/
443 KASSERT(is->is_irq >= 0);
444 KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
445 }
446
447 static void
448 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
449 {
450
451 irq %= BCM2836_NIRQPERCPU;
452 strlcpy(buf, bcm2836mp_sources[irq], len);
453 }
454
455
456 #ifdef MULTIPROCESSOR
457 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
458 {
459
460 /* Enable IRQ and not FIQ */
461 bus_space_write_4(al_iot, al_ioh,
462 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_cpuid), 1);
463 }
464
465
466 static void
467 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
468 {
469 KASSERT(pic != NULL);
470 KASSERT(pic != &bcm2835_pic);
471 KASSERT(pic->pic_cpus != NULL);
472
473 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
474
475 bus_space_write_4(al_iot, al_ioh,
476 BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
477 }
478
479 int
480 bcm2836mp_ipi_handler(void *priv)
481 {
482 const struct cpu_info *ci = curcpu();
483 const cpuid_t cpuid = ci->ci_cpuid;
484 uint32_t ipimask, bit;
485
486 ipimask = bus_space_read_4(al_iot, al_ioh,
487 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
488 bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_MAILBOX0_CLRN(cpuid),
489 ipimask);
490
491 while ((bit = ffs(ipimask)) > 0) {
492 const u_int ipi = bit - 1;
493 switch (ipi) {
494 case IPI_AST:
495 pic_ipi_ast(priv);
496 break;
497 case IPI_NOP:
498 pic_ipi_nop(priv);
499 break;
500 #ifdef __HAVE_PREEMPTION
501 case IPI_KPREEMPT:
502 pic_ipi_kpreempt(priv);
503 break;
504 #endif
505 case IPI_XCALL:
506 pic_ipi_xcall(priv);
507 break;
508 case IPI_GENERIC:
509 pic_ipi_generic(priv);
510 break;
511 case IPI_SHOOTDOWN:
512 pic_ipi_shootdown(priv);
513 break;
514 #ifdef DDB
515 case IPI_DDB:
516 pic_ipi_ddb(priv);
517 break;
518 #endif
519 }
520 ipimask &= ~__BIT(ipi);
521 }
522
523 return 1;
524 }
525
526 void
527 bcm2836mp_intr_init(struct cpu_info *ci)
528 {
529 const cpuid_t cpuid = ci->ci_cpuid;
530 struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
531
532 pic->pic_cpus = ci->ci_kcpuset;
533 pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
534
535 intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
536 IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
537
538 /* clock interrupt will attach with gtmr */
539 if (cpuid == 0)
540 return;
541
542 intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
543 IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
544
545 }
546 #endif
547
548 #endif
549