1 /*
2 * Copyright 2015 Andrew Turner.
3 * Copyright 2016 Svatopluk Kraus
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #include "opt_platform.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/cpuset.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/proc.h>
41 #include <sys/rman.h>
42 #ifdef SMP
43 #include <sys/smp.h>
44 #endif
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48 #include <machine/resource.h>
49 #ifdef SMP
50 #include <machine/smp.h>
51 #endif
52
53 #include <dev/ofw/ofw_bus_subr.h>
54 #include <dev/ofw/ofw_bus.h>
55
56 #include "pic_if.h"
57
58 #define BCM_LINTC_CONTROL_REG 0x00
59 #define BCM_LINTC_PRESCALER_REG 0x08
60 #define BCM_LINTC_GPU_ROUTING_REG 0x0c
61 #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10
62 #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14
63 #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4)
64 #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4)
65 #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4)
66 #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16)
67 #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16)
68 #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16)
69 #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16)
70 #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16)
71 #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16)
72 #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16)
73 #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16)
74
75 /* Prescaler Register */
76 #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */
77
78 /* GPU Interrupt Routing Register */
79 #define BCM_LINTC_GIRR_IRQ_CORE(n) (n)
80 #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2)
81
82 /* PMU Interrupt Routing Register */
83 #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n))
84 #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4))
85
86 /* Timer Config Register */
87 #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n))
88 #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4))
89
90 /* MBOX Config Register */
91 #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n))
92 #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4))
93
94 #define BCM_LINTC_CNTPSIRQ_IRQ 0
95 #define BCM_LINTC_CNTPNSIRQ_IRQ 1
96 #define BCM_LINTC_CNTHPIRQ_IRQ 2
97 #define BCM_LINTC_CNTVIRQ_IRQ 3
98 #define BCM_LINTC_MBOX0_IRQ 4
99 #define BCM_LINTC_MBOX1_IRQ 5
100 #define BCM_LINTC_MBOX2_IRQ 6
101 #define BCM_LINTC_MBOX3_IRQ 7
102 #define BCM_LINTC_GPU_IRQ 8
103 #define BCM_LINTC_PMU_IRQ 9
104 #define BCM_LINTC_AXI_IRQ 10
105 #define BCM_LINTC_LTIMER_IRQ 11
106
107 #define BCM_LINTC_NIRQS 12
108
109 #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ
110 #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ
111 #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ
112 #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ
113
114 #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ)
115 #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ)
116 #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ)
117 #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ)
118 #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ)
119 #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ)
120 #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ)
121
122 #define BCM_LINTC_UP_PENDING_MASK \
123 (BCM_LINTC_TIMER0_IRQ_MASK | \
124 BCM_LINTC_TIMER1_IRQ_MASK | \
125 BCM_LINTC_TIMER2_IRQ_MASK | \
126 BCM_LINTC_TIMER3_IRQ_MASK | \
127 BCM_LINTC_GPU_IRQ_MASK | \
128 BCM_LINTC_PMU_IRQ_MASK)
129
130 #define BCM_LINTC_SMP_PENDING_MASK \
131 (BCM_LINTC_UP_PENDING_MASK | \
132 BCM_LINTC_MBOX0_IRQ_MASK)
133
134 #ifdef SMP
135 #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK
136 #else
137 #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK
138 #endif
139
140 struct bcm_lintc_irqsrc {
141 struct intr_irqsrc bli_isrc;
142 u_int bli_irq;
143 union {
144 u_int bli_mask; /* for timers */
145 u_int bli_value; /* for GPU */
146 };
147 };
148
149 struct bcm_lintc_softc {
150 device_t bls_dev;
151 struct mtx bls_mtx;
152 struct resource * bls_mem;
153 bus_space_tag_t bls_bst;
154 bus_space_handle_t bls_bsh;
155 struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS];
156 };
157
158 static struct bcm_lintc_softc *bcm_lintc_sc;
159
160 #ifdef SMP
161 #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */
162 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
163 #endif
164
165 #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx)
166 #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx)
167 #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \
168 device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
169 #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx)
170
171 #define bcm_lintc_read_4(sc, reg) \
172 bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
173 #define bcm_lintc_write_4(sc, reg, val) \
174 bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
175
176 static inline void
bcm_lintc_rwreg_clr(struct bcm_lintc_softc * sc,uint32_t reg,uint32_t mask)177 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
178 uint32_t mask)
179 {
180
181 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
182 }
183
184 static inline void
bcm_lintc_rwreg_set(struct bcm_lintc_softc * sc,uint32_t reg,uint32_t mask)185 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
186 uint32_t mask)
187 {
188
189 bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
190 }
191
192 static void
bcm_lintc_timer_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)193 bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
194 {
195 cpuset_t *cpus;
196 uint32_t cpu;
197
198 cpus = &bli->bli_isrc.isrc_cpu;
199
200 BCM_LINTC_LOCK(sc);
201 for (cpu = 0; cpu < 4; cpu++)
202 if (CPU_ISSET(cpu, cpus))
203 bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
204 bli->bli_mask);
205 BCM_LINTC_UNLOCK(sc);
206 }
207
208 static void
bcm_lintc_timer_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)209 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
210 {
211 cpuset_t *cpus;
212 uint32_t cpu;
213
214 cpus = &bli->bli_isrc.isrc_cpu;
215
216 BCM_LINTC_LOCK(sc);
217 for (cpu = 0; cpu < 4; cpu++)
218 if (CPU_ISSET(cpu, cpus))
219 bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
220 bli->bli_mask);
221 BCM_LINTC_UNLOCK(sc);
222 }
223
224 static inline void
bcm_lintc_gpu_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)225 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
226 {
227
228 /* It's accessed just and only by one core. */
229 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
230 }
231
232 static inline void
bcm_lintc_gpu_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)233 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
234 {
235
236 /* It's accessed just and only by one core. */
237 bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
238 }
239
240 static inline void
bcm_lintc_pmu_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)241 bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
242 {
243 cpuset_t *cpus;
244 uint32_t cpu, mask;
245
246 mask = 0;
247 cpus = &bli->bli_isrc.isrc_cpu;
248
249 BCM_LINTC_LOCK(sc);
250 for (cpu = 0; cpu < 4; cpu++)
251 if (CPU_ISSET(cpu, cpus))
252 mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
253 /* Write-clear register. */
254 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
255 BCM_LINTC_UNLOCK(sc);
256 }
257
258 static inline void
bcm_lintc_pmu_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)259 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
260 {
261 cpuset_t *cpus;
262 uint32_t cpu, mask;
263
264 mask = 0;
265 cpus = &bli->bli_isrc.isrc_cpu;
266
267 BCM_LINTC_LOCK(sc);
268 for (cpu = 0; cpu < 4; cpu++)
269 if (CPU_ISSET(cpu, cpus))
270 mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
271 /* Write-set register. */
272 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
273 BCM_LINTC_UNLOCK(sc);
274 }
275
276 static void
bcm_lintc_mask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)277 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
278 {
279
280 switch (bli->bli_irq) {
281 case BCM_LINTC_TIMER0_IRQ:
282 case BCM_LINTC_TIMER1_IRQ:
283 case BCM_LINTC_TIMER2_IRQ:
284 case BCM_LINTC_TIMER3_IRQ:
285 bcm_lintc_timer_mask(sc, bli);
286 return;
287 case BCM_LINTC_MBOX0_IRQ:
288 case BCM_LINTC_MBOX1_IRQ:
289 case BCM_LINTC_MBOX2_IRQ:
290 case BCM_LINTC_MBOX3_IRQ:
291 return;
292 case BCM_LINTC_GPU_IRQ:
293 bcm_lintc_gpu_mask(sc, bli);
294 return;
295 case BCM_LINTC_PMU_IRQ:
296 bcm_lintc_pmu_mask(sc, bli);
297 return;
298 default:
299 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
300 }
301 }
302
303 static void
bcm_lintc_unmask(struct bcm_lintc_softc * sc,struct bcm_lintc_irqsrc * bli)304 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
305 {
306
307 switch (bli->bli_irq) {
308 case BCM_LINTC_TIMER0_IRQ:
309 case BCM_LINTC_TIMER1_IRQ:
310 case BCM_LINTC_TIMER2_IRQ:
311 case BCM_LINTC_TIMER3_IRQ:
312 bcm_lintc_timer_unmask(sc, bli);
313 return;
314 case BCM_LINTC_MBOX0_IRQ:
315 case BCM_LINTC_MBOX1_IRQ:
316 case BCM_LINTC_MBOX2_IRQ:
317 case BCM_LINTC_MBOX3_IRQ:
318 return;
319 case BCM_LINTC_GPU_IRQ:
320 bcm_lintc_gpu_unmask(sc, bli);
321 return;
322 case BCM_LINTC_PMU_IRQ:
323 bcm_lintc_pmu_unmask(sc, bli);
324 return;
325 default:
326 panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
327 }
328 }
329
330 #ifdef SMP
331 static inline void
bcm_lintc_ipi_write(struct bcm_lintc_softc * sc,cpuset_t cpus,u_int ipi)332 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
333 {
334 u_int cpu;
335 uint32_t mask;
336
337 mask = 1 << ipi;
338 for (cpu = 0; cpu < mp_ncpus; cpu++)
339 if (CPU_ISSET(cpu, &cpus))
340 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
341 mask);
342 }
343
344 static inline void
bcm_lintc_ipi_dispatch(struct bcm_lintc_softc * sc,u_int cpu,struct trapframe * tf)345 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
346 struct trapframe *tf)
347 {
348 u_int ipi;
349 uint32_t mask;
350
351 mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
352 if (mask == 0) {
353 device_printf(sc->bls_dev, "Spurious ipi detected\n");
354 return;
355 }
356
357 for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
358 if ((mask & 0x01) == 0)
359 continue;
360 /*
361 * Clear an IPI before dispatching to not miss anyone
362 * and make sure that it's observed by everybody.
363 */
364 bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
365 #if defined(__aarch64__)
366 dsb(sy);
367 #else
368 dsb();
369 #endif
370 intr_ipi_dispatch(ipi);
371 }
372 }
373 #endif
374
375 static inline void
bcm_lintc_irq_dispatch(struct bcm_lintc_softc * sc,u_int irq,struct trapframe * tf)376 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
377 struct trapframe *tf)
378 {
379 struct bcm_lintc_irqsrc *bli;
380
381 bli = &sc->bls_isrcs[irq];
382 if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
383 device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
384 }
385
386 static int
bcm_lintc_intr(void * arg)387 bcm_lintc_intr(void *arg)
388 {
389 struct bcm_lintc_softc *sc;
390 u_int cpu;
391 uint32_t num, reg;
392 struct trapframe *tf;
393
394 sc = arg;
395 cpu = PCPU_GET(cpuid);
396 tf = curthread->td_intr_frame;
397
398 for (num = 0; ; num++) {
399 reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
400 if ((reg & BCM_LINTC_PENDING_MASK) == 0)
401 break;
402 #ifdef SMP
403 if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
404 bcm_lintc_ipi_dispatch(sc, cpu, tf);
405 #endif
406 if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
407 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
408 if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
409 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
410 if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
411 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
412 if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
413 bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
414 if (reg & BCM_LINTC_GPU_IRQ_MASK)
415 bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
416 if (reg & BCM_LINTC_PMU_IRQ_MASK)
417 bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
418
419 arm_irq_memory_barrier(0); /* XXX */
420 }
421 reg &= ~BCM_LINTC_PENDING_MASK;
422 if (reg != 0)
423 device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
424 else if (num == 0 && bootverbose)
425 device_printf(sc->bls_dev, "Spurious interrupt detected\n");
426
427 return (FILTER_HANDLED);
428 }
429
430 static void
bcm_lintc_disable_intr(device_t dev,struct intr_irqsrc * isrc)431 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
432 {
433
434 bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
435 }
436
437 static void
bcm_lintc_enable_intr(device_t dev,struct intr_irqsrc * isrc)438 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
439 {
440 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
441
442 arm_irq_memory_barrier(bli->bli_irq);
443 bcm_lintc_unmask(device_get_softc(dev), bli);
444 }
445
446 static int
bcm_lintc_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)447 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
448 struct intr_irqsrc **isrcp)
449 {
450 struct intr_map_data_fdt *daf;
451 struct bcm_lintc_softc *sc;
452
453 if (data->type != INTR_MAP_DATA_FDT)
454 return (ENOTSUP);
455
456 daf = (struct intr_map_data_fdt *)data;
457 if (daf->ncells > 2 || daf->cells[0] >= BCM_LINTC_NIRQS)
458 return (EINVAL);
459
460 /* TODO: handle IRQ type here */
461
462 sc = device_get_softc(dev);
463 *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
464 return (0);
465 }
466
467 static void
bcm_lintc_pre_ithread(device_t dev,struct intr_irqsrc * isrc)468 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
469 {
470 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
471
472 if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
473 bcm_lintc_gpu_mask(device_get_softc(dev), bli);
474 else {
475 /*
476 * Handler for PPI interrupt does not make sense much unless
477 * there is one bound ithread for each core for it. Thus the
478 * interrupt can be masked on current core only while ithread
479 * bounded to this core ensures unmasking on the same core.
480 */
481 panic ("%s: handlers are not supported", __func__);
482 }
483 }
484
485 static void
bcm_lintc_post_ithread(device_t dev,struct intr_irqsrc * isrc)486 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
487 {
488 struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
489
490 if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
491 bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
492 else {
493 /* See comment in bcm_lintc_pre_ithread(). */
494 panic ("%s: handlers are not supported", __func__);
495 }
496 }
497
498 static void
bcm_lintc_post_filter(device_t dev,struct intr_irqsrc * isrc)499 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
500 {
501 }
502
503 static int
bcm_lintc_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)504 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
505 struct resource *res, struct intr_map_data *data)
506 {
507 struct bcm_lintc_softc *sc;
508
509 if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
510 sc = device_get_softc(dev);
511 BCM_LINTC_LOCK(sc);
512 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
513 BCM_LINTC_UNLOCK(sc);
514 }
515 return (0);
516 }
517
518 #ifdef SMP
519 static void
bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc * sc,u_int cpu,u_int irq,uint32_t reg,uint32_t mask)520 bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
521 uint32_t reg, uint32_t mask)
522 {
523
524 if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
525 bcm_lintc_rwreg_set(sc, reg, mask);
526 }
527
528 static void
bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc * sc,u_int cpu)529 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
530 {
531 struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
532
533 if (intr_isrc_init_on_cpu(isrc, cpu)) {
534 /* Write-set register. */
535 bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
536 BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
537 }
538 }
539
540 static void
bcm_lintc_init_secondary(device_t dev,uint32_t rootnum)541 bcm_lintc_init_secondary(device_t dev, uint32_t rootnum)
542 {
543 u_int cpu;
544 struct bcm_lintc_softc *sc;
545
546 cpu = PCPU_GET(cpuid);
547 sc = device_get_softc(dev);
548
549 BCM_LINTC_LOCK(sc);
550 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
551 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
552 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
553 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
554 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
555 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
556 bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
557 BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
558 bcm_lintc_init_pmu_on_ap(sc, cpu);
559 BCM_LINTC_UNLOCK(sc);
560 }
561
562 static void
bcm_lintc_ipi_send(device_t dev,struct intr_irqsrc * isrc,cpuset_t cpus,u_int ipi)563 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
564 u_int ipi)
565 {
566 struct bcm_lintc_softc *sc = device_get_softc(dev);
567
568 KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
569 ("%s: bad ISRC %p argument", __func__, isrc));
570 bcm_lintc_ipi_write(sc, cpus, ipi);
571 }
572
573 static int
bcm_lintc_ipi_setup(device_t dev,u_int ipi,struct intr_irqsrc ** isrcp)574 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
575 {
576 struct bcm_lintc_softc *sc = device_get_softc(dev);
577
578 KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
579
580 *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
581 return (0);
582 }
583 #endif
584
585 static int
bcm_lintc_pic_attach(struct bcm_lintc_softc * sc)586 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
587 {
588 struct bcm_lintc_irqsrc *bisrcs;
589 struct intr_pic *pic;
590 int error;
591 u_int flags;
592 uint32_t irq;
593 const char *name;
594 intptr_t xref;
595
596 bisrcs = sc->bls_isrcs;
597 name = device_get_nameunit(sc->bls_dev);
598 for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
599 bisrcs[irq].bli_irq = irq;
600 switch (irq) {
601 case BCM_LINTC_TIMER0_IRQ:
602 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
603 flags = INTR_ISRCF_PPI;
604 break;
605 case BCM_LINTC_TIMER1_IRQ:
606 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
607 flags = INTR_ISRCF_PPI;
608 break;
609 case BCM_LINTC_TIMER2_IRQ:
610 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
611 flags = INTR_ISRCF_PPI;
612 break;
613 case BCM_LINTC_TIMER3_IRQ:
614 bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
615 flags = INTR_ISRCF_PPI;
616 break;
617 case BCM_LINTC_MBOX0_IRQ:
618 case BCM_LINTC_MBOX1_IRQ:
619 case BCM_LINTC_MBOX2_IRQ:
620 case BCM_LINTC_MBOX3_IRQ:
621 bisrcs[irq].bli_value = 0; /* not used */
622 flags = INTR_ISRCF_IPI;
623 break;
624 case BCM_LINTC_GPU_IRQ:
625 bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
626 flags = 0;
627 break;
628 case BCM_LINTC_PMU_IRQ:
629 bisrcs[irq].bli_value = 0; /* not used */
630 flags = INTR_ISRCF_PPI;
631 break;
632 default:
633 bisrcs[irq].bli_value = 0; /* not used */
634 flags = 0;
635 break;
636 }
637
638 error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
639 flags, "%s,%u", name, irq);
640 if (error != 0)
641 return (error);
642 }
643
644 xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
645 pic = intr_pic_register(sc->bls_dev, xref);
646 if (pic == NULL)
647 return (ENXIO);
648
649 error = intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc,
650 INTR_ROOT_IRQ);
651 if (error != 0)
652 return (error);
653
654 #ifdef SMP
655 error = intr_ipi_pic_register(sc->bls_dev, 0);
656 if (error != 0)
657 return (error);
658 #endif
659
660 return (0);
661 }
662
663 static int
bcm_lintc_probe(device_t dev)664 bcm_lintc_probe(device_t dev)
665 {
666
667 if (!ofw_bus_status_okay(dev))
668 return (ENXIO);
669
670 if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
671 return (ENXIO);
672 if (!ofw_bus_has_prop(dev, "interrupt-controller"))
673 return (ENXIO);
674 device_set_desc(dev, "BCM2836 Interrupt Controller");
675 return (BUS_PROBE_DEFAULT);
676 }
677
678 static int
bcm_lintc_attach(device_t dev)679 bcm_lintc_attach(device_t dev)
680 {
681 struct bcm_lintc_softc *sc;
682 int cpu, rid;
683
684 sc = device_get_softc(dev);
685
686 sc->bls_dev = dev;
687 if (bcm_lintc_sc != NULL)
688 return (ENXIO);
689
690 rid = 0;
691 sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
692 RF_ACTIVE);
693 if (sc->bls_mem == NULL) {
694 device_printf(dev, "could not allocate memory resource\n");
695 return (ENXIO);
696 }
697
698 sc->bls_bst = rman_get_bustag(sc->bls_mem);
699 sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
700
701 bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
702 bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
703
704 /* Disable all timers on all cores. */
705 for (cpu = 0; cpu < 4; cpu++)
706 bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
707
708 #ifdef SMP
709 /* Enable mailbox 0 on all cores used for IPI. */
710 for (cpu = 0; cpu < 4; cpu++)
711 bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
712 BCM_LINTC_MCR_IRQ_EN_MBOX(0));
713 #endif
714
715 if (bcm_lintc_pic_attach(sc) != 0) {
716 device_printf(dev, "could not attach PIC\n");
717 return (ENXIO);
718 }
719
720 BCM_LINTC_LOCK_INIT(sc);
721 bcm_lintc_sc = sc;
722 return (0);
723 }
724
725 static device_method_t bcm_lintc_methods[] = {
726 DEVMETHOD(device_probe, bcm_lintc_probe),
727 DEVMETHOD(device_attach, bcm_lintc_attach),
728
729 DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr),
730 DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr),
731 DEVMETHOD(pic_map_intr, bcm_lintc_map_intr),
732 DEVMETHOD(pic_post_filter, bcm_lintc_post_filter),
733 DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread),
734 DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread),
735 DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr),
736 #ifdef SMP
737 DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary),
738 DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send),
739 DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup),
740 #endif
741
742 DEVMETHOD_END
743 };
744
745 static driver_t bcm_lintc_driver = {
746 "lintc",
747 bcm_lintc_methods,
748 sizeof(struct bcm_lintc_softc),
749 };
750
751 EARLY_DRIVER_MODULE(lintc, simplebus, bcm_lintc_driver, 0, 0,
752 BUS_PASS_INTERRUPT);
753