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