xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2836.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
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 __FBSDID("$FreeBSD$");
31 
32 #include "opt_platform.h"
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/cpuset.h>
38 #include <sys/kernel.h>
39 #include <sys/module.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 #ifdef INTRNG
57 #include "pic_if.h"
58 #else
59 #include <arm/broadcom/bcm2835/bcm2836.h>
60 
61 #define	ARM_LOCAL_BASE	0x40000000
62 #define	ARM_LOCAL_SIZE	0x00001000
63 
64 #define	ARM_LOCAL_CONTROL		0x00
65 #define	ARM_LOCAL_PRESCALER		0x08
66 #define	 PRESCALER_19_2			0x80000000 /* 19.2 MHz */
67 #define	ARM_LOCAL_INT_TIMER(n)		(0x40 + (n) * 4)
68 #define	ARM_LOCAL_INT_MAILBOX(n)	(0x50 + (n) * 4)
69 #define	ARM_LOCAL_INT_PENDING(n)	(0x60 + (n) * 4)
70 #define	 INT_PENDING_MASK		0x011f
71 #define	MAILBOX0_IRQ			4
72 #define	MAILBOX0_IRQEN			(1 << 0)
73 #endif
74 
75 #ifdef INTRNG
76 #define	BCM_LINTC_CONTROL_REG		0x00
77 #define	BCM_LINTC_PRESCALER_REG		0x08
78 #define	BCM_LINTC_GPU_ROUTING_REG	0x0c
79 #define	BCM_LINTC_PMU_ROUTING_SET_REG	0x10
80 #define	BCM_LINTC_PMU_ROUTING_CLR_REG	0x14
81 #define	BCM_LINTC_TIMER_CFG_REG(n)	(0x40 + (n) * 4)
82 #define	BCM_LINTC_MBOX_CFG_REG(n)	(0x50 + (n) * 4)
83 #define	BCM_LINTC_PENDING_REG(n)	(0x60 + (n) * 4)
84 #define	BCM_LINTC_MBOX0_SET_REG(n)	(0x80 + (n) * 16)
85 #define	BCM_LINTC_MBOX1_SET_REG(n)	(0x84 + (n) * 16)
86 #define	BCM_LINTC_MBOX2_SET_REG(n)	(0x88 + (n) * 16)
87 #define	BCM_LINTC_MBOX3_SET_REG(n)	(0x8C + (n) * 16)
88 #define	BCM_LINTC_MBOX0_CLR_REG(n)	(0xC0 + (n) * 16)
89 #define	BCM_LINTC_MBOX1_CLR_REG(n)	(0xC4 + (n) * 16)
90 #define	BCM_LINTC_MBOX2_CLR_REG(n)	(0xC8 + (n) * 16)
91 #define	BCM_LINTC_MBOX3_CLR_REG(n)	(0xCC + (n) * 16)
92 
93 /* Prescaler Register */
94 #define	BCM_LINTC_PSR_19_2		0x80000000	/* 19.2 MHz */
95 
96 /* GPU Interrupt Routing Register */
97 #define	BCM_LINTC_GIRR_IRQ_CORE(n)	(n)
98 #define	BCM_LINTC_GIRR_FIQ_CORE(n)	((n) << 2)
99 
100 /* PMU Interrupt Routing Register */
101 #define	BCM_LINTC_PIRR_IRQ_EN_CORE(n)	(1 << (n))
102 #define	BCM_LINTC_PIRR_FIQ_EN_CORE(n)	(1 << ((n) + 4))
103 
104 /* Timer Config Register */
105 #define	BCM_LINTC_TCR_IRQ_EN_TIMER(n)	(1 << (n))
106 #define	BCM_LINTC_TCR_FIQ_EN_TIMER(n)	(1 << ((n) + 4))
107 
108 /* MBOX Config Register */
109 #define	BCM_LINTC_MCR_IRQ_EN_MBOX(n)	(1 << (n))
110 #define	BCM_LINTC_MCR_FIQ_EN_MBOX(n)	(1 << ((n) + 4))
111 
112 #define	BCM_LINTC_CNTPSIRQ_IRQ		0
113 #define	BCM_LINTC_CNTPNSIRQ_IRQ		1
114 #define	BCM_LINTC_CNTHPIRQ_IRQ		2
115 #define	BCM_LINTC_CNTVIRQ_IRQ		3
116 #define	BCM_LINTC_MBOX0_IRQ		4
117 #define	BCM_LINTC_MBOX1_IRQ		5
118 #define	BCM_LINTC_MBOX2_IRQ		6
119 #define	BCM_LINTC_MBOX3_IRQ		7
120 #define	BCM_LINTC_GPU_IRQ		8
121 #define	BCM_LINTC_PMU_IRQ		9
122 #define	BCM_LINTC_AXI_IRQ		10
123 #define	BCM_LINTC_LTIMER_IRQ		11
124 
125 #define	BCM_LINTC_NIRQS			12
126 
127 #define	BCM_LINTC_TIMER0_IRQ		BCM_LINTC_CNTPSIRQ_IRQ
128 #define	BCM_LINTC_TIMER1_IRQ		BCM_LINTC_CNTPNSIRQ_IRQ
129 #define	BCM_LINTC_TIMER2_IRQ		BCM_LINTC_CNTHPIRQ_IRQ
130 #define	BCM_LINTC_TIMER3_IRQ		BCM_LINTC_CNTVIRQ_IRQ
131 
132 #define	BCM_LINTC_TIMER0_IRQ_MASK	(1 << BCM_LINTC_TIMER0_IRQ)
133 #define	BCM_LINTC_TIMER1_IRQ_MASK	(1 << BCM_LINTC_TIMER1_IRQ)
134 #define	BCM_LINTC_TIMER2_IRQ_MASK	(1 << BCM_LINTC_TIMER2_IRQ)
135 #define	BCM_LINTC_TIMER3_IRQ_MASK	(1 << BCM_LINTC_TIMER3_IRQ)
136 #define	BCM_LINTC_MBOX0_IRQ_MASK	(1 << BCM_LINTC_MBOX0_IRQ)
137 #define	BCM_LINTC_GPU_IRQ_MASK		(1 << BCM_LINTC_GPU_IRQ)
138 #define	BCM_LINTC_PMU_IRQ_MASK		(1 << BCM_LINTC_PMU_IRQ)
139 
140 #define	BCM_LINTC_UP_PENDING_MASK	\
141     (BCM_LINTC_TIMER0_IRQ_MASK |	\
142      BCM_LINTC_TIMER1_IRQ_MASK |	\
143      BCM_LINTC_TIMER2_IRQ_MASK |	\
144      BCM_LINTC_TIMER3_IRQ_MASK |	\
145      BCM_LINTC_GPU_IRQ_MASK |		\
146      BCM_LINTC_PMU_IRQ_MASK)
147 
148 #define	BCM_LINTC_SMP_PENDING_MASK	\
149     (BCM_LINTC_UP_PENDING_MASK |	\
150      BCM_LINTC_MBOX0_IRQ_MASK)
151 
152 #ifdef SMP
153 #define BCM_LINTC_PENDING_MASK		BCM_LINTC_SMP_PENDING_MASK
154 #else
155 #define BCM_LINTC_PENDING_MASK		BCM_LINTC_UP_PENDING_MASK
156 #endif
157 
158 struct bcm_lintc_irqsrc {
159 	struct intr_irqsrc	bli_isrc;
160 	u_int			bli_irq;
161 	union {
162 		u_int		bli_mask;	/* for timers */
163 		u_int		bli_value;	/* for GPU */
164 	};
165 };
166 
167 struct bcm_lintc_softc {
168 	device_t		bls_dev;
169 	struct mtx		bls_mtx;
170 	struct resource *	bls_mem;
171 	bus_space_tag_t		bls_bst;
172 	bus_space_handle_t	bls_bsh;
173 	struct bcm_lintc_irqsrc	bls_isrcs[BCM_LINTC_NIRQS];
174 };
175 
176 static struct bcm_lintc_softc *bcm_lintc_sc;
177 
178 #ifdef SMP
179 #define BCM_LINTC_NIPIS		32	/* only mailbox 0 is used for IPI */
180 CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
181 #endif
182 
183 #define	BCM_LINTC_LOCK(sc)		mtx_lock_spin(&(sc)->bls_mtx)
184 #define	BCM_LINTC_UNLOCK(sc)		mtx_unlock_spin(&(sc)->bls_mtx)
185 #define	BCM_LINTC_LOCK_INIT(sc)		mtx_init(&(sc)->bls_mtx,	\
186     device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
187 #define	BCM_LINTC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->bls_mtx)
188 
189 #define	bcm_lintc_read_4(sc, reg)		\
190     bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
191 #define	bcm_lintc_write_4(sc, reg, val)		\
192     bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
193 
194 static inline void
195 bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
196     uint32_t mask)
197 {
198 
199 	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
200 }
201 
202 static inline void
203 bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
204     uint32_t mask)
205 {
206 
207 	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
208 }
209 
210 static void
211 bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
212 {
213 	cpuset_t *cpus;
214 	uint32_t cpu;
215 
216 	cpus = &bli->bli_isrc.isrc_cpu;
217 
218 	BCM_LINTC_LOCK(sc);
219 	for (cpu = 0; cpu < 4; cpu++)
220 		if (CPU_ISSET(cpu, cpus))
221 			bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
222 			    bli->bli_mask);
223 	BCM_LINTC_UNLOCK(sc);
224 }
225 
226 static void
227 bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
228 {
229 	cpuset_t *cpus;
230 	uint32_t cpu;
231 
232 	cpus = &bli->bli_isrc.isrc_cpu;
233 
234 	BCM_LINTC_LOCK(sc);
235 	for (cpu = 0; cpu < 4; cpu++)
236 		if (CPU_ISSET(cpu, cpus))
237 			bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
238 			    bli->bli_mask);
239 	BCM_LINTC_UNLOCK(sc);
240 }
241 
242 static inline void
243 bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
244 {
245 
246 	/* It's accessed just and only by one core. */
247 	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
248 }
249 
250 static inline void
251 bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
252 {
253 
254 	/* It's accessed just and only by one core. */
255 	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
256 }
257 
258 static inline void
259 bcm_lintc_pmu_mask(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-clear register. */
272 	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
273 	BCM_LINTC_UNLOCK(sc);
274 }
275 
276 static inline void
277 bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
278 {
279 	cpuset_t *cpus;
280 	uint32_t cpu, mask;
281 
282 	mask = 0;
283 	cpus = &bli->bli_isrc.isrc_cpu;
284 
285 	BCM_LINTC_LOCK(sc);
286 	for (cpu = 0; cpu < 4; cpu++)
287 		if (CPU_ISSET(cpu, cpus))
288 			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
289 	/* Write-set register. */
290 	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
291 	BCM_LINTC_UNLOCK(sc);
292 }
293 
294 static void
295 bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
296 {
297 
298 	switch (bli->bli_irq) {
299 	case BCM_LINTC_TIMER0_IRQ:
300 	case BCM_LINTC_TIMER1_IRQ:
301 	case BCM_LINTC_TIMER2_IRQ:
302 	case BCM_LINTC_TIMER3_IRQ:
303 		bcm_lintc_timer_mask(sc, bli);
304 		return;
305 	case BCM_LINTC_MBOX0_IRQ:
306 	case BCM_LINTC_MBOX1_IRQ:
307 	case BCM_LINTC_MBOX2_IRQ:
308 	case BCM_LINTC_MBOX3_IRQ:
309 		return;
310 	case BCM_LINTC_GPU_IRQ:
311 		bcm_lintc_gpu_mask(sc, bli);
312 		return;
313 	case BCM_LINTC_PMU_IRQ:
314 		bcm_lintc_pmu_mask(sc, bli);
315 		return;
316 	default:
317 		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
318 	}
319 }
320 
321 static void
322 bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
323 {
324 
325 	switch (bli->bli_irq) {
326 	case BCM_LINTC_TIMER0_IRQ:
327 	case BCM_LINTC_TIMER1_IRQ:
328 	case BCM_LINTC_TIMER2_IRQ:
329 	case BCM_LINTC_TIMER3_IRQ:
330 		bcm_lintc_timer_unmask(sc, bli);
331 		return;
332 	case BCM_LINTC_MBOX0_IRQ:
333 	case BCM_LINTC_MBOX1_IRQ:
334 	case BCM_LINTC_MBOX2_IRQ:
335 	case BCM_LINTC_MBOX3_IRQ:
336 		return;
337 	case BCM_LINTC_GPU_IRQ:
338 		bcm_lintc_gpu_unmask(sc, bli);
339 		return;
340 	case BCM_LINTC_PMU_IRQ:
341 		bcm_lintc_pmu_unmask(sc, bli);
342 		return;
343 	default:
344 		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
345 	}
346 }
347 
348 #ifdef SMP
349 static inline void
350 bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
351 {
352 	u_int cpu;
353 	uint32_t mask;
354 
355 	mask = 1 << ipi;
356 	for (cpu = 0; cpu < mp_ncpus; cpu++)
357 		if (CPU_ISSET(cpu, &cpus))
358 			bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
359 			    mask);
360 }
361 
362 static inline void
363 bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
364     struct trapframe *tf)
365 {
366 	u_int ipi;
367 	uint32_t mask;
368 
369 	mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
370 	if (mask == 0) {
371 		device_printf(sc->bls_dev, "Spurious ipi detected\n");
372 		return;
373 	}
374 
375 	for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
376 		if ((mask & 0x01) == 0)
377 			continue;
378 		/*
379 		 * Clear an IPI before dispatching to not miss anyone
380 		 * and make sure that it's observed by everybody.
381 		 */
382 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
383 		dsb();
384 		intr_ipi_dispatch(ipi, tf);
385 	}
386 }
387 #endif
388 
389 static inline void
390 bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
391     struct trapframe *tf)
392 {
393 	struct bcm_lintc_irqsrc *bli;
394 
395 	bli = &sc->bls_isrcs[irq];
396 	if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
397 		device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
398 }
399 
400 static int
401 bcm_lintc_intr(void *arg)
402 {
403 	struct bcm_lintc_softc *sc;
404 	u_int cpu;
405 	uint32_t num, reg;
406 	struct trapframe *tf;
407 
408 	sc = arg;
409 	cpu = PCPU_GET(cpuid);
410 	tf = curthread->td_intr_frame;
411 
412 	for (num = 0; ; num++) {
413 		reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
414 		if ((reg & BCM_LINTC_PENDING_MASK) == 0)
415 			break;
416 #ifdef SMP
417 		if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
418 			bcm_lintc_ipi_dispatch(sc, cpu, tf);
419 #endif
420 		if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
421 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
422 		if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
423 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
424 		if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
425 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
426 		if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
427 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
428 		if (reg & BCM_LINTC_GPU_IRQ_MASK)
429 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
430 		if (reg & BCM_LINTC_PMU_IRQ_MASK)
431 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
432 
433 		arm_irq_memory_barrier(0); /* XXX */
434 	}
435 	reg &= ~BCM_LINTC_PENDING_MASK;
436 	if (reg != 0)
437 		device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
438 	else if (num == 0)
439 		device_printf(sc->bls_dev, "Spurious interrupt detected\n");
440 
441 	return (FILTER_HANDLED);
442 }
443 
444 static void
445 bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
446 {
447 
448 	bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
449 }
450 
451 static void
452 bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
453 {
454 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
455 
456 	arm_irq_memory_barrier(bli->bli_irq);
457 	bcm_lintc_unmask(device_get_softc(dev), bli);
458 }
459 
460 static int
461 bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
462     struct intr_irqsrc **isrcp)
463 {
464 	struct intr_map_data_fdt *daf;
465 	struct bcm_lintc_softc *sc;
466 
467 	if (data->type != INTR_MAP_DATA_FDT)
468 		return (ENOTSUP);
469 
470 	daf = (struct intr_map_data_fdt *)data;
471 	if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS)
472 		return (EINVAL);
473 
474 	sc = device_get_softc(dev);
475 	*isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
476 	return (0);
477 }
478 
479 static void
480 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
481 {
482 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
483 
484 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
485 		bcm_lintc_gpu_mask(device_get_softc(dev), bli);
486 	else {
487 		/*
488 		 * Handler for PPI interrupt does not make sense much unless
489 		 * there is one bound ithread for each core for it. Thus the
490 		 * interrupt can be masked on current core only while ithread
491 		 * bounded to this core ensures unmasking on the same core.
492 		 */
493 		panic ("%s: handlers are not supported", __func__);
494 	}
495 }
496 
497 static void
498 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
499 {
500 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
501 
502 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
503 		bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
504 	else {
505 		/* See comment in bcm_lintc_pre_ithread(). */
506 		panic ("%s: handlers are not supported", __func__);
507 	}
508 }
509 
510 static void
511 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
512 {
513 }
514 
515 static int
516 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
517     struct resource *res, struct intr_map_data *data)
518 {
519 	struct bcm_lintc_softc *sc;
520 
521 	if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
522 		sc = device_get_softc(dev);
523 		BCM_LINTC_LOCK(sc);
524 		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
525 		BCM_LINTC_UNLOCK(sc);
526 	}
527 	return (0);
528 }
529 
530 #ifdef SMP
531 static void
532 bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
533     uint32_t reg, uint32_t mask)
534 {
535 
536 	if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
537 		bcm_lintc_rwreg_set(sc, reg, mask);
538 }
539 
540 static void
541 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
542 {
543 	struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
544 
545 	if (intr_isrc_init_on_cpu(isrc, cpu)) {
546 		/* Write-set register. */
547 		bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
548 		    BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
549 	}
550 }
551 
552 static void
553 bcm_lintc_init_secondary(device_t dev)
554 {
555 	u_int cpu;
556 	struct bcm_lintc_softc *sc;
557 
558 	cpu = PCPU_GET(cpuid);
559 	sc = device_get_softc(dev);
560 
561 	BCM_LINTC_LOCK(sc);
562 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
563 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
564 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
565 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
566 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
567 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
568 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
569 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
570 	bcm_lintc_init_pmu_on_ap(sc, cpu);
571 	BCM_LINTC_UNLOCK(sc);
572 }
573 
574 static void
575 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
576     u_int ipi)
577 {
578 	struct bcm_lintc_softc *sc = device_get_softc(dev);
579 
580 	KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
581 	    ("%s: bad ISRC %p argument", __func__, isrc));
582 	bcm_lintc_ipi_write(sc, cpus, ipi);
583 }
584 
585 static int
586 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
587 {
588 	struct bcm_lintc_softc *sc = device_get_softc(dev);
589 
590 	KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
591 
592 	*isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
593 	return (0);
594 }
595 #endif
596 
597 static int
598 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
599 {
600 	struct bcm_lintc_irqsrc *bisrcs;
601 	struct intr_pic *pic;
602 	int error;
603 	u_int flags;
604 	uint32_t irq;
605 	const char *name;
606 	intptr_t xref;
607 
608 	bisrcs = sc->bls_isrcs;
609 	name = device_get_nameunit(sc->bls_dev);
610 	for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
611 		bisrcs[irq].bli_irq = irq;
612 		switch (irq) {
613 		case BCM_LINTC_TIMER0_IRQ:
614 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
615 			flags = INTR_ISRCF_PPI;
616 			break;
617 		case BCM_LINTC_TIMER1_IRQ:
618 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
619 			flags = INTR_ISRCF_PPI;
620 			break;
621 		case BCM_LINTC_TIMER2_IRQ:
622 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
623 			flags = INTR_ISRCF_PPI;
624 			break;
625 		case BCM_LINTC_TIMER3_IRQ:
626 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
627 			flags = INTR_ISRCF_PPI;
628 			break;
629 		case BCM_LINTC_MBOX0_IRQ:
630 		case BCM_LINTC_MBOX1_IRQ:
631 		case BCM_LINTC_MBOX2_IRQ:
632 		case BCM_LINTC_MBOX3_IRQ:
633 			bisrcs[irq].bli_value = 0;	/* not used */
634 			flags = INTR_ISRCF_IPI;
635 			break;
636 		case BCM_LINTC_GPU_IRQ:
637 			bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
638 			flags = 0;
639 			break;
640 		case BCM_LINTC_PMU_IRQ:
641 			bisrcs[irq].bli_value = 0;	/* not used */
642 			flags = INTR_ISRCF_PPI;
643 			break;
644 		default:
645 			bisrcs[irq].bli_value = 0;	/* not used */
646 			flags = 0;
647 			break;
648 		}
649 
650 		error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
651 		    flags, "%s,%u", name, irq);
652 		if (error != 0)
653 			return (error);
654 	}
655 
656 	xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
657 	pic = intr_pic_register(sc->bls_dev, xref);
658 	if (pic == NULL)
659 		return (ENXIO);
660 
661 	return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
662 }
663 
664 static int
665 bcm_lintc_probe(device_t dev)
666 {
667 
668 	if (!ofw_bus_status_okay(dev))
669 		return (ENXIO);
670 
671 	if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
672 		return (ENXIO);
673 	device_set_desc(dev, "BCM2836 Interrupt Controller");
674 	return (BUS_PROBE_DEFAULT);
675 }
676 
677 static int
678 bcm_lintc_attach(device_t dev)
679 {
680 	struct bcm_lintc_softc *sc;
681 	int cpu, rid;
682 
683 	sc = device_get_softc(dev);
684 
685 	sc->bls_dev = dev;
686 	if (bcm_lintc_sc != NULL)
687 		return (ENXIO);
688 
689 	rid = 0;
690 	sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
691 	    RF_ACTIVE);
692 	if (sc->bls_mem == NULL) {
693 		device_printf(dev, "could not allocate memory resource\n");
694 		return (ENXIO);
695 	}
696 
697 	sc->bls_bst = rman_get_bustag(sc->bls_mem);
698 	sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
699 
700 	bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
701 	bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
702 
703 	/* Disable all timers on all cores. */
704 	for (cpu = 0; cpu < 4; cpu++)
705 		bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
706 
707 #ifdef SMP
708 	/* Enable mailbox 0 on all cores used for IPI. */
709 	for (cpu = 0; cpu < 4; cpu++)
710 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
711 		    BCM_LINTC_MCR_IRQ_EN_MBOX(0));
712 #endif
713 
714 	if (bcm_lintc_pic_attach(sc) != 0) {
715 		device_printf(dev, "could not attach PIC\n");
716 		return (ENXIO);
717 	}
718 
719 	BCM_LINTC_LOCK_INIT(sc);
720 	bcm_lintc_sc = sc;
721 	return (0);
722 }
723 
724 static device_method_t bcm_lintc_methods[] = {
725 	DEVMETHOD(device_probe,		bcm_lintc_probe),
726 	DEVMETHOD(device_attach,	bcm_lintc_attach),
727 
728 	DEVMETHOD(pic_disable_intr,	bcm_lintc_disable_intr),
729 	DEVMETHOD(pic_enable_intr,	bcm_lintc_enable_intr),
730 	DEVMETHOD(pic_map_intr,		bcm_lintc_map_intr),
731 	DEVMETHOD(pic_post_filter,	bcm_lintc_post_filter),
732 	DEVMETHOD(pic_post_ithread,	bcm_lintc_post_ithread),
733 	DEVMETHOD(pic_pre_ithread,	bcm_lintc_pre_ithread),
734 	DEVMETHOD(pic_setup_intr,	bcm_lintc_setup_intr),
735 #ifdef SMP
736 	DEVMETHOD(pic_init_secondary,	bcm_lintc_init_secondary),
737 	DEVMETHOD(pic_ipi_send,		bcm_lintc_ipi_send),
738 	DEVMETHOD(pic_ipi_setup,	bcm_lintc_ipi_setup),
739 #endif
740 
741 	DEVMETHOD_END
742 };
743 
744 static driver_t bcm_lintc_driver = {
745 	"local_intc",
746 	bcm_lintc_methods,
747 	sizeof(struct bcm_lintc_softc),
748 };
749 
750 static devclass_t bcm_lintc_devclass;
751 
752 EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
753     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
754 #else
755 /*
756  * A driver for features of the bcm2836.
757  */
758 
759 struct bcm2836_softc {
760 	device_t	 sc_dev;
761 	struct resource *sc_mem;
762 };
763 
764 static device_identify_t bcm2836_identify;
765 static device_probe_t bcm2836_probe;
766 static device_attach_t bcm2836_attach;
767 
768 struct bcm2836_softc *softc;
769 
770 static void
771 bcm2836_identify(driver_t *driver, device_t parent)
772 {
773 
774 	if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
775 		device_printf(parent, "add child failed\n");
776 }
777 
778 static int
779 bcm2836_probe(device_t dev)
780 {
781 
782 	if (softc != NULL)
783 		return (ENXIO);
784 
785 	device_set_desc(dev, "Broadcom bcm2836");
786 
787 	return (BUS_PROBE_DEFAULT);
788 }
789 
790 static int
791 bcm2836_attach(device_t dev)
792 {
793 	int i, rid;
794 
795 	softc = device_get_softc(dev);
796 	softc->sc_dev = dev;
797 
798 	rid = 0;
799 	softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
800 	    ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE,
801 	    RF_ACTIVE);
802 	if (softc->sc_mem == NULL) {
803 		device_printf(dev, "could not allocate memory resource\n");
804 		return (ENXIO);
805 	}
806 
807 	bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
808 	bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
809 
810 	for (i = 0; i < 4; i++)
811 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
812 
813 	for (i = 0; i < 4; i++)
814 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
815 
816 	return (0);
817 }
818 
819 int
820 bcm2836_get_next_irq(int last_irq)
821 {
822 	uint32_t reg;
823 	int cpu;
824 	int irq;
825 
826 	cpu = PCPU_GET(cpuid);
827 
828 	reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
829 	reg &= INT_PENDING_MASK;
830 	if (reg == 0)
831 		return (-1);
832 
833 	irq = ffs(reg) - 1;
834 
835 	return (irq);
836 }
837 
838 void
839 bcm2836_mask_irq(uintptr_t irq)
840 {
841 	uint32_t reg;
842 #ifdef SMP
843 	int cpu;
844 #endif
845 	int i;
846 
847 	if (irq < MAILBOX0_IRQ) {
848 		for (i = 0; i < 4; i++) {
849 			reg = bus_read_4(softc->sc_mem,
850 			    ARM_LOCAL_INT_TIMER(i));
851 			reg &= ~(1 << irq);
852 			bus_write_4(softc->sc_mem,
853 			    ARM_LOCAL_INT_TIMER(i), reg);
854 		}
855 #ifdef SMP
856 	} else if (irq == MAILBOX0_IRQ) {
857 		/* Mailbox 0 for IPI */
858 		cpu = PCPU_GET(cpuid);
859 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
860 		reg &= ~MAILBOX0_IRQEN;
861 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
862 #endif
863 	}
864 }
865 
866 void
867 bcm2836_unmask_irq(uintptr_t irq)
868 {
869 	uint32_t reg;
870 #ifdef SMP
871 	int cpu;
872 #endif
873 	int i;
874 
875 	if (irq < MAILBOX0_IRQ) {
876 		for (i = 0; i < 4; i++) {
877 			reg = bus_read_4(softc->sc_mem,
878 			    ARM_LOCAL_INT_TIMER(i));
879 			reg |= (1 << irq);
880 			bus_write_4(softc->sc_mem,
881 			    ARM_LOCAL_INT_TIMER(i), reg);
882 		}
883 #ifdef SMP
884 	} else if (irq == MAILBOX0_IRQ) {
885 		/* Mailbox 0 for IPI */
886 		cpu = PCPU_GET(cpuid);
887 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
888 		reg |= MAILBOX0_IRQEN;
889 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
890 #endif
891 	}
892 }
893 
894 static device_method_t bcm2836_methods[] = {
895 	/* Device interface */
896 	DEVMETHOD(device_identify,	bcm2836_identify),
897 	DEVMETHOD(device_probe,		bcm2836_probe),
898 	DEVMETHOD(device_attach,	bcm2836_attach),
899 
900 	DEVMETHOD_END
901 };
902 
903 static devclass_t bcm2836_devclass;
904 
905 static driver_t bcm2836_driver = {
906 	"bcm2836",
907 	bcm2836_methods,
908 	sizeof(struct bcm2836_softc),
909 };
910 
911 EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
912     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
913 #endif
914