xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2836.c (revision a5ff72cb0e51a7675d4e2b5810a2b6dad5b91960)
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 bcm_lintc_softc *sc;
465 
466 	if (data->type != INTR_MAP_DATA_FDT)
467 		return (ENOTSUP);
468 	if (data->fdt.ncells != 1 || data->fdt.cells[0] >= BCM_LINTC_NIRQS)
469 		return (EINVAL);
470 
471 	sc = device_get_softc(dev);
472 	*isrcp = &sc->bls_isrcs[data->fdt.cells[0]].bli_isrc;
473 	return (0);
474 }
475 
476 static void
477 bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
478 {
479 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
480 
481 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
482 		bcm_lintc_gpu_mask(device_get_softc(dev), bli);
483 	else {
484 		/*
485 		 * Handler for PPI interrupt does not make sense much unless
486 		 * there is one bound ithread for each core for it. Thus the
487 		 * interrupt can be masked on current core only while ithread
488 		 * bounded to this core ensures unmasking on the same core.
489 		 */
490 		panic ("%s: handlers are not supported", __func__);
491 	}
492 }
493 
494 static void
495 bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
496 {
497 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
498 
499 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
500 		bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
501 	else {
502 		/* See comment in bcm_lintc_pre_ithread(). */
503 		panic ("%s: handlers are not supported", __func__);
504 	}
505 }
506 
507 static void
508 bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
509 {
510 }
511 
512 static int
513 bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
514     struct resource *res, struct intr_map_data *data)
515 {
516 	struct bcm_lintc_softc *sc;
517 
518 	if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
519 		sc = device_get_softc(dev);
520 		BCM_LINTC_LOCK(sc);
521 		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
522 		BCM_LINTC_UNLOCK(sc);
523 	}
524 	return (0);
525 }
526 
527 #ifdef SMP
528 static void
529 bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
530     uint32_t reg, uint32_t mask)
531 {
532 
533 	if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
534 		bcm_lintc_rwreg_set(sc, reg, mask);
535 }
536 
537 static void
538 bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
539 {
540 	struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
541 
542 	if (intr_isrc_init_on_cpu(isrc, cpu)) {
543 		/* Write-set register. */
544 		bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
545 		    BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
546 	}
547 }
548 
549 static void
550 bcm_lintc_init_secondary(device_t dev)
551 {
552 	u_int cpu;
553 	struct bcm_lintc_softc *sc;
554 
555 	cpu = PCPU_GET(cpuid);
556 	sc = device_get_softc(dev);
557 
558 	BCM_LINTC_LOCK(sc);
559 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
560 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
561 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
562 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
563 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
564 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
565 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
566 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
567 	bcm_lintc_init_pmu_on_ap(sc, cpu);
568 	BCM_LINTC_UNLOCK(sc);
569 }
570 
571 static void
572 bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
573     u_int ipi)
574 {
575 	struct bcm_lintc_softc *sc = device_get_softc(dev);
576 
577 	KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
578 	    ("%s: bad ISRC %p argument", __func__, isrc));
579 	bcm_lintc_ipi_write(sc, cpus, ipi);
580 }
581 
582 static int
583 bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
584 {
585 	struct bcm_lintc_softc *sc = device_get_softc(dev);
586 
587 	KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
588 
589 	*isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
590 	return (0);
591 }
592 #endif
593 
594 static int
595 bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
596 {
597 	struct bcm_lintc_irqsrc *bisrcs;
598 	int error;
599 	u_int flags;
600 	uint32_t irq;
601 	const char *name;
602 	intptr_t xref;
603 
604 	bisrcs = sc->bls_isrcs;
605 	name = device_get_nameunit(sc->bls_dev);
606 	for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
607 		bisrcs[irq].bli_irq = irq;
608 		switch (irq) {
609 		case BCM_LINTC_TIMER0_IRQ:
610 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
611 			flags = INTR_ISRCF_PPI;
612 			break;
613 		case BCM_LINTC_TIMER1_IRQ:
614 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
615 			flags = INTR_ISRCF_PPI;
616 			break;
617 		case BCM_LINTC_TIMER2_IRQ:
618 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
619 			flags = INTR_ISRCF_PPI;
620 			break;
621 		case BCM_LINTC_TIMER3_IRQ:
622 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
623 			flags = INTR_ISRCF_PPI;
624 			break;
625 		case BCM_LINTC_MBOX0_IRQ:
626 		case BCM_LINTC_MBOX1_IRQ:
627 		case BCM_LINTC_MBOX2_IRQ:
628 		case BCM_LINTC_MBOX3_IRQ:
629 			bisrcs[irq].bli_value = 0;	/* not used */
630 			flags = INTR_ISRCF_IPI;
631 			break;
632 		case BCM_LINTC_GPU_IRQ:
633 			bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
634 			flags = 0;
635 			break;
636 		case BCM_LINTC_PMU_IRQ:
637 			bisrcs[irq].bli_value = 0;	/* not used */
638 			flags = INTR_ISRCF_PPI;
639 			break;
640 		default:
641 			bisrcs[irq].bli_value = 0;	/* not used */
642 			flags = 0;
643 			break;
644 		}
645 
646 		error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
647 		    flags, "%s,%u", name, irq);
648 		if (error != 0)
649 			return (error);
650 	}
651 
652 	xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
653 	error = intr_pic_register(sc->bls_dev, xref);
654 	if (error != 0)
655 		return (error);
656 
657 	return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
658 }
659 
660 static int
661 bcm_lintc_probe(device_t dev)
662 {
663 
664 	if (!ofw_bus_status_okay(dev))
665 		return (ENXIO);
666 
667 	if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
668 		return (ENXIO);
669 	device_set_desc(dev, "BCM2836 Interrupt Controller");
670 	return (BUS_PROBE_DEFAULT);
671 }
672 
673 static int
674 bcm_lintc_attach(device_t dev)
675 {
676 	struct bcm_lintc_softc *sc;
677 	int cpu, rid;
678 
679 	sc = device_get_softc(dev);
680 
681 	sc->bls_dev = dev;
682 	if (bcm_lintc_sc != NULL)
683 		return (ENXIO);
684 
685 	rid = 0;
686 	sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
687 	    RF_ACTIVE);
688 	if (sc->bls_mem == NULL) {
689 		device_printf(dev, "could not allocate memory resource\n");
690 		return (ENXIO);
691 	}
692 
693 	sc->bls_bst = rman_get_bustag(sc->bls_mem);
694 	sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
695 
696 	bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
697 	bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
698 
699 	/* Disable all timers on all cores. */
700 	for (cpu = 0; cpu < 4; cpu++)
701 		bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
702 
703 #ifdef SMP
704 	/* Enable mailbox 0 on all cores used for IPI. */
705 	for (cpu = 0; cpu < 4; cpu++)
706 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
707 		    BCM_LINTC_MCR_IRQ_EN_MBOX(0));
708 #endif
709 
710 	if (bcm_lintc_pic_attach(sc) != 0) {
711 		device_printf(dev, "could not attach PIC\n");
712 		return (ENXIO);
713 	}
714 
715 	BCM_LINTC_LOCK_INIT(sc);
716 	bcm_lintc_sc = sc;
717 	return (0);
718 }
719 
720 static device_method_t bcm_lintc_methods[] = {
721 	DEVMETHOD(device_probe,		bcm_lintc_probe),
722 	DEVMETHOD(device_attach,	bcm_lintc_attach),
723 
724 	DEVMETHOD(pic_disable_intr,	bcm_lintc_disable_intr),
725 	DEVMETHOD(pic_enable_intr,	bcm_lintc_enable_intr),
726 	DEVMETHOD(pic_map_intr,		bcm_lintc_map_intr),
727 	DEVMETHOD(pic_post_filter,	bcm_lintc_post_filter),
728 	DEVMETHOD(pic_post_ithread,	bcm_lintc_post_ithread),
729 	DEVMETHOD(pic_pre_ithread,	bcm_lintc_pre_ithread),
730 	DEVMETHOD(pic_setup_intr,	bcm_lintc_setup_intr),
731 #ifdef SMP
732 	DEVMETHOD(pic_init_secondary,	bcm_lintc_init_secondary),
733 	DEVMETHOD(pic_ipi_send,		bcm_lintc_ipi_send),
734 	DEVMETHOD(pic_ipi_setup,	bcm_lintc_ipi_setup),
735 #endif
736 
737 	DEVMETHOD_END
738 };
739 
740 static driver_t bcm_lintc_driver = {
741 	"local_intc",
742 	bcm_lintc_methods,
743 	sizeof(struct bcm_lintc_softc),
744 };
745 
746 static devclass_t bcm_lintc_devclass;
747 
748 EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
749     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
750 #else
751 /*
752  * A driver for features of the bcm2836.
753  */
754 
755 struct bcm2836_softc {
756 	device_t	 sc_dev;
757 	struct resource *sc_mem;
758 };
759 
760 static device_identify_t bcm2836_identify;
761 static device_probe_t bcm2836_probe;
762 static device_attach_t bcm2836_attach;
763 
764 struct bcm2836_softc *softc;
765 
766 static void
767 bcm2836_identify(driver_t *driver, device_t parent)
768 {
769 
770 	if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
771 		device_printf(parent, "add child failed\n");
772 }
773 
774 static int
775 bcm2836_probe(device_t dev)
776 {
777 
778 	if (softc != NULL)
779 		return (ENXIO);
780 
781 	device_set_desc(dev, "Broadcom bcm2836");
782 
783 	return (BUS_PROBE_DEFAULT);
784 }
785 
786 static int
787 bcm2836_attach(device_t dev)
788 {
789 	int i, rid;
790 
791 	softc = device_get_softc(dev);
792 	softc->sc_dev = dev;
793 
794 	rid = 0;
795 	softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
796 	    ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE,
797 	    RF_ACTIVE);
798 	if (softc->sc_mem == NULL) {
799 		device_printf(dev, "could not allocate memory resource\n");
800 		return (ENXIO);
801 	}
802 
803 	bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
804 	bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
805 
806 	for (i = 0; i < 4; i++)
807 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
808 
809 	for (i = 0; i < 4; i++)
810 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
811 
812 	return (0);
813 }
814 
815 int
816 bcm2836_get_next_irq(int last_irq)
817 {
818 	uint32_t reg;
819 	int cpu;
820 	int irq;
821 
822 	cpu = PCPU_GET(cpuid);
823 
824 	reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
825 	reg &= INT_PENDING_MASK;
826 	if (reg == 0)
827 		return (-1);
828 
829 	irq = ffs(reg) - 1;
830 
831 	return (irq);
832 }
833 
834 void
835 bcm2836_mask_irq(uintptr_t irq)
836 {
837 	uint32_t reg;
838 #ifdef SMP
839 	int cpu;
840 #endif
841 	int i;
842 
843 	if (irq < MAILBOX0_IRQ) {
844 		for (i = 0; i < 4; i++) {
845 			reg = bus_read_4(softc->sc_mem,
846 			    ARM_LOCAL_INT_TIMER(i));
847 			reg &= ~(1 << irq);
848 			bus_write_4(softc->sc_mem,
849 			    ARM_LOCAL_INT_TIMER(i), reg);
850 		}
851 #ifdef SMP
852 	} else if (irq == MAILBOX0_IRQ) {
853 		/* Mailbox 0 for IPI */
854 		cpu = PCPU_GET(cpuid);
855 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
856 		reg &= ~MAILBOX0_IRQEN;
857 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
858 #endif
859 	}
860 }
861 
862 void
863 bcm2836_unmask_irq(uintptr_t irq)
864 {
865 	uint32_t reg;
866 #ifdef SMP
867 	int cpu;
868 #endif
869 	int i;
870 
871 	if (irq < MAILBOX0_IRQ) {
872 		for (i = 0; i < 4; i++) {
873 			reg = bus_read_4(softc->sc_mem,
874 			    ARM_LOCAL_INT_TIMER(i));
875 			reg |= (1 << irq);
876 			bus_write_4(softc->sc_mem,
877 			    ARM_LOCAL_INT_TIMER(i), reg);
878 		}
879 #ifdef SMP
880 	} else if (irq == MAILBOX0_IRQ) {
881 		/* Mailbox 0 for IPI */
882 		cpu = PCPU_GET(cpuid);
883 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
884 		reg |= MAILBOX0_IRQEN;
885 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
886 #endif
887 	}
888 }
889 
890 static device_method_t bcm2836_methods[] = {
891 	/* Device interface */
892 	DEVMETHOD(device_identify,	bcm2836_identify),
893 	DEVMETHOD(device_probe,		bcm2836_probe),
894 	DEVMETHOD(device_attach,	bcm2836_attach),
895 
896 	DEVMETHOD_END
897 };
898 
899 static devclass_t bcm2836_devclass;
900 
901 static driver_t bcm2836_driver = {
902 	"bcm2836",
903 	bcm2836_methods,
904 	sizeof(struct bcm2836_softc),
905 };
906 
907 EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
908     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
909 #endif
910