xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2836.c (revision 079171874c9bf263b69e3af10784ad2bcd1fe699)
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 	int error;
602 	u_int flags;
603 	uint32_t irq;
604 	const char *name;
605 	intptr_t xref;
606 
607 	bisrcs = sc->bls_isrcs;
608 	name = device_get_nameunit(sc->bls_dev);
609 	for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
610 		bisrcs[irq].bli_irq = irq;
611 		switch (irq) {
612 		case BCM_LINTC_TIMER0_IRQ:
613 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
614 			flags = INTR_ISRCF_PPI;
615 			break;
616 		case BCM_LINTC_TIMER1_IRQ:
617 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
618 			flags = INTR_ISRCF_PPI;
619 			break;
620 		case BCM_LINTC_TIMER2_IRQ:
621 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
622 			flags = INTR_ISRCF_PPI;
623 			break;
624 		case BCM_LINTC_TIMER3_IRQ:
625 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
626 			flags = INTR_ISRCF_PPI;
627 			break;
628 		case BCM_LINTC_MBOX0_IRQ:
629 		case BCM_LINTC_MBOX1_IRQ:
630 		case BCM_LINTC_MBOX2_IRQ:
631 		case BCM_LINTC_MBOX3_IRQ:
632 			bisrcs[irq].bli_value = 0;	/* not used */
633 			flags = INTR_ISRCF_IPI;
634 			break;
635 		case BCM_LINTC_GPU_IRQ:
636 			bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
637 			flags = 0;
638 			break;
639 		case BCM_LINTC_PMU_IRQ:
640 			bisrcs[irq].bli_value = 0;	/* not used */
641 			flags = INTR_ISRCF_PPI;
642 			break;
643 		default:
644 			bisrcs[irq].bli_value = 0;	/* not used */
645 			flags = 0;
646 			break;
647 		}
648 
649 		error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
650 		    flags, "%s,%u", name, irq);
651 		if (error != 0)
652 			return (error);
653 	}
654 
655 	xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
656 	error = intr_pic_register(sc->bls_dev, xref);
657 	if (error != 0)
658 		return (error);
659 
660 	return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
661 }
662 
663 static int
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 	device_set_desc(dev, "BCM2836 Interrupt Controller");
673 	return (BUS_PROBE_DEFAULT);
674 }
675 
676 static int
677 bcm_lintc_attach(device_t dev)
678 {
679 	struct bcm_lintc_softc *sc;
680 	int cpu, rid;
681 
682 	sc = device_get_softc(dev);
683 
684 	sc->bls_dev = dev;
685 	if (bcm_lintc_sc != NULL)
686 		return (ENXIO);
687 
688 	rid = 0;
689 	sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
690 	    RF_ACTIVE);
691 	if (sc->bls_mem == NULL) {
692 		device_printf(dev, "could not allocate memory resource\n");
693 		return (ENXIO);
694 	}
695 
696 	sc->bls_bst = rman_get_bustag(sc->bls_mem);
697 	sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
698 
699 	bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
700 	bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
701 
702 	/* Disable all timers on all cores. */
703 	for (cpu = 0; cpu < 4; cpu++)
704 		bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
705 
706 #ifdef SMP
707 	/* Enable mailbox 0 on all cores used for IPI. */
708 	for (cpu = 0; cpu < 4; cpu++)
709 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
710 		    BCM_LINTC_MCR_IRQ_EN_MBOX(0));
711 #endif
712 
713 	if (bcm_lintc_pic_attach(sc) != 0) {
714 		device_printf(dev, "could not attach PIC\n");
715 		return (ENXIO);
716 	}
717 
718 	BCM_LINTC_LOCK_INIT(sc);
719 	bcm_lintc_sc = sc;
720 	return (0);
721 }
722 
723 static device_method_t bcm_lintc_methods[] = {
724 	DEVMETHOD(device_probe,		bcm_lintc_probe),
725 	DEVMETHOD(device_attach,	bcm_lintc_attach),
726 
727 	DEVMETHOD(pic_disable_intr,	bcm_lintc_disable_intr),
728 	DEVMETHOD(pic_enable_intr,	bcm_lintc_enable_intr),
729 	DEVMETHOD(pic_map_intr,		bcm_lintc_map_intr),
730 	DEVMETHOD(pic_post_filter,	bcm_lintc_post_filter),
731 	DEVMETHOD(pic_post_ithread,	bcm_lintc_post_ithread),
732 	DEVMETHOD(pic_pre_ithread,	bcm_lintc_pre_ithread),
733 	DEVMETHOD(pic_setup_intr,	bcm_lintc_setup_intr),
734 #ifdef SMP
735 	DEVMETHOD(pic_init_secondary,	bcm_lintc_init_secondary),
736 	DEVMETHOD(pic_ipi_send,		bcm_lintc_ipi_send),
737 	DEVMETHOD(pic_ipi_setup,	bcm_lintc_ipi_setup),
738 #endif
739 
740 	DEVMETHOD_END
741 };
742 
743 static driver_t bcm_lintc_driver = {
744 	"local_intc",
745 	bcm_lintc_methods,
746 	sizeof(struct bcm_lintc_softc),
747 };
748 
749 static devclass_t bcm_lintc_devclass;
750 
751 EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
752     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
753 #else
754 /*
755  * A driver for features of the bcm2836.
756  */
757 
758 struct bcm2836_softc {
759 	device_t	 sc_dev;
760 	struct resource *sc_mem;
761 };
762 
763 static device_identify_t bcm2836_identify;
764 static device_probe_t bcm2836_probe;
765 static device_attach_t bcm2836_attach;
766 
767 struct bcm2836_softc *softc;
768 
769 static void
770 bcm2836_identify(driver_t *driver, device_t parent)
771 {
772 
773 	if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
774 		device_printf(parent, "add child failed\n");
775 }
776 
777 static int
778 bcm2836_probe(device_t dev)
779 {
780 
781 	if (softc != NULL)
782 		return (ENXIO);
783 
784 	device_set_desc(dev, "Broadcom bcm2836");
785 
786 	return (BUS_PROBE_DEFAULT);
787 }
788 
789 static int
790 bcm2836_attach(device_t dev)
791 {
792 	int i, rid;
793 
794 	softc = device_get_softc(dev);
795 	softc->sc_dev = dev;
796 
797 	rid = 0;
798 	softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
799 	    ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE,
800 	    RF_ACTIVE);
801 	if (softc->sc_mem == NULL) {
802 		device_printf(dev, "could not allocate memory resource\n");
803 		return (ENXIO);
804 	}
805 
806 	bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
807 	bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
808 
809 	for (i = 0; i < 4; i++)
810 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
811 
812 	for (i = 0; i < 4; i++)
813 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
814 
815 	return (0);
816 }
817 
818 int
819 bcm2836_get_next_irq(int last_irq)
820 {
821 	uint32_t reg;
822 	int cpu;
823 	int irq;
824 
825 	cpu = PCPU_GET(cpuid);
826 
827 	reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
828 	reg &= INT_PENDING_MASK;
829 	if (reg == 0)
830 		return (-1);
831 
832 	irq = ffs(reg) - 1;
833 
834 	return (irq);
835 }
836 
837 void
838 bcm2836_mask_irq(uintptr_t irq)
839 {
840 	uint32_t reg;
841 #ifdef SMP
842 	int cpu;
843 #endif
844 	int i;
845 
846 	if (irq < MAILBOX0_IRQ) {
847 		for (i = 0; i < 4; i++) {
848 			reg = bus_read_4(softc->sc_mem,
849 			    ARM_LOCAL_INT_TIMER(i));
850 			reg &= ~(1 << irq);
851 			bus_write_4(softc->sc_mem,
852 			    ARM_LOCAL_INT_TIMER(i), reg);
853 		}
854 #ifdef SMP
855 	} else if (irq == MAILBOX0_IRQ) {
856 		/* Mailbox 0 for IPI */
857 		cpu = PCPU_GET(cpuid);
858 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
859 		reg &= ~MAILBOX0_IRQEN;
860 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
861 #endif
862 	}
863 }
864 
865 void
866 bcm2836_unmask_irq(uintptr_t irq)
867 {
868 	uint32_t reg;
869 #ifdef SMP
870 	int cpu;
871 #endif
872 	int i;
873 
874 	if (irq < MAILBOX0_IRQ) {
875 		for (i = 0; i < 4; i++) {
876 			reg = bus_read_4(softc->sc_mem,
877 			    ARM_LOCAL_INT_TIMER(i));
878 			reg |= (1 << irq);
879 			bus_write_4(softc->sc_mem,
880 			    ARM_LOCAL_INT_TIMER(i), reg);
881 		}
882 #ifdef SMP
883 	} else if (irq == MAILBOX0_IRQ) {
884 		/* Mailbox 0 for IPI */
885 		cpu = PCPU_GET(cpuid);
886 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
887 		reg |= MAILBOX0_IRQEN;
888 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
889 #endif
890 	}
891 }
892 
893 static device_method_t bcm2836_methods[] = {
894 	/* Device interface */
895 	DEVMETHOD(device_identify,	bcm2836_identify),
896 	DEVMETHOD(device_probe,		bcm2836_probe),
897 	DEVMETHOD(device_attach,	bcm2836_attach),
898 
899 	DEVMETHOD_END
900 };
901 
902 static devclass_t bcm2836_devclass;
903 
904 static driver_t bcm2836_driver = {
905 	"bcm2836",
906 	bcm2836_methods,
907 	sizeof(struct bcm2836_softc),
908 };
909 
910 EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
911     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
912 #endif
913