xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2836.c (revision 9346e9130d7ae72b1a6fadb36de85c835074b883)
14e46a66eSAndrew Turner /*
24e46a66eSAndrew Turner  * Copyright 2015 Andrew Turner.
3120b6fc9SSvatopluk Kraus  * Copyright 2016 Svatopluk Kraus
44e46a66eSAndrew Turner  * All rights reserved.
54e46a66eSAndrew Turner  *
64e46a66eSAndrew Turner  * Redistribution and use in source and binary forms, with or without
74e46a66eSAndrew Turner  * modification, are permitted provided that the following conditions are
84e46a66eSAndrew Turner  * met:
94e46a66eSAndrew Turner  *
104e46a66eSAndrew Turner  *  1. Redistributions of source code must retain the above copyright
114e46a66eSAndrew Turner  *     notice, this list of conditions and the following disclaimer.
124e46a66eSAndrew Turner  *  2. Redistributions in binary form must reproduce the above copyright
134e46a66eSAndrew Turner  *     notice, this list of conditions and the following disclaimer in the
144e46a66eSAndrew Turner  *     documentation and/or other materials provided with the distribution.
154e46a66eSAndrew Turner  *
164e46a66eSAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174e46a66eSAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184e46a66eSAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194e46a66eSAndrew Turner  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
204e46a66eSAndrew Turner  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214e46a66eSAndrew Turner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224e46a66eSAndrew Turner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
234e46a66eSAndrew Turner  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
244e46a66eSAndrew Turner  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
254e46a66eSAndrew Turner  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
264e46a66eSAndrew Turner  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274e46a66eSAndrew Turner  */
284e46a66eSAndrew Turner 
294e46a66eSAndrew Turner #include <sys/cdefs.h>
304e46a66eSAndrew Turner __FBSDID("$FreeBSD$");
314e46a66eSAndrew Turner 
32120b6fc9SSvatopluk Kraus #include "opt_platform.h"
33120b6fc9SSvatopluk Kraus 
344e46a66eSAndrew Turner #include <sys/param.h>
354e46a66eSAndrew Turner #include <sys/systm.h>
364e46a66eSAndrew Turner #include <sys/bus.h>
37120b6fc9SSvatopluk Kraus #include <sys/cpuset.h>
384e46a66eSAndrew Turner #include <sys/kernel.h>
394e46a66eSAndrew Turner #include <sys/module.h>
40120b6fc9SSvatopluk Kraus #include <sys/proc.h>
414e46a66eSAndrew Turner #include <sys/rman.h>
42120b6fc9SSvatopluk Kraus #ifdef SMP
43120b6fc9SSvatopluk Kraus #include <sys/smp.h>
44120b6fc9SSvatopluk Kraus #endif
454e46a66eSAndrew Turner 
464e46a66eSAndrew Turner #include <machine/bus.h>
47120b6fc9SSvatopluk Kraus #include <machine/intr.h>
484e46a66eSAndrew Turner #include <machine/resource.h>
49120b6fc9SSvatopluk Kraus #ifdef SMP
50120b6fc9SSvatopluk Kraus #include <machine/smp.h>
51120b6fc9SSvatopluk Kraus #endif
524e46a66eSAndrew Turner 
534e46a66eSAndrew Turner #include <dev/ofw/ofw_bus_subr.h>
544e46a66eSAndrew Turner #include <dev/ofw/ofw_bus.h>
554e46a66eSAndrew Turner 
5659c3cb81SAndrew Turner #ifdef INTRNG
57120b6fc9SSvatopluk Kraus #include "pic_if.h"
58120b6fc9SSvatopluk Kraus #else
594e46a66eSAndrew Turner #include <arm/broadcom/bcm2835/bcm2836.h>
604e46a66eSAndrew Turner 
614e46a66eSAndrew Turner #define	ARM_LOCAL_BASE	0x40000000
624e46a66eSAndrew Turner #define	ARM_LOCAL_SIZE	0x00001000
634e46a66eSAndrew Turner 
644e46a66eSAndrew Turner #define	ARM_LOCAL_CONTROL		0x00
654e46a66eSAndrew Turner #define	ARM_LOCAL_PRESCALER		0x08
664e46a66eSAndrew Turner #define	 PRESCALER_19_2			0x80000000 /* 19.2 MHz */
674e46a66eSAndrew Turner #define	ARM_LOCAL_INT_TIMER(n)		(0x40 + (n) * 4)
684e46a66eSAndrew Turner #define	ARM_LOCAL_INT_MAILBOX(n)	(0x50 + (n) * 4)
694e46a66eSAndrew Turner #define	ARM_LOCAL_INT_PENDING(n)	(0x60 + (n) * 4)
703084b64cSSvatopluk Kraus #define	 INT_PENDING_MASK		0x011f
71962940ceSLuiz Otavio O Souza #define	MAILBOX0_IRQ			4
72962940ceSLuiz Otavio O Souza #define	MAILBOX0_IRQEN			(1 << 0)
73120b6fc9SSvatopluk Kraus #endif
744e46a66eSAndrew Turner 
7559c3cb81SAndrew Turner #ifdef INTRNG
76120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CONTROL_REG		0x00
77120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PRESCALER_REG		0x08
78120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GPU_ROUTING_REG	0x0c
79120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_ROUTING_SET_REG	0x10
80120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_ROUTING_CLR_REG	0x14
81120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER_CFG_REG(n)	(0x40 + (n) * 4)
82120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX_CFG_REG(n)	(0x50 + (n) * 4)
83120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PENDING_REG(n)	(0x60 + (n) * 4)
84120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_SET_REG(n)	(0x80 + (n) * 16)
85120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX1_SET_REG(n)	(0x84 + (n) * 16)
86120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX2_SET_REG(n)	(0x88 + (n) * 16)
87120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX3_SET_REG(n)	(0x8C + (n) * 16)
88120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_CLR_REG(n)	(0xC0 + (n) * 16)
89120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX1_CLR_REG(n)	(0xC4 + (n) * 16)
90120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX2_CLR_REG(n)	(0xC8 + (n) * 16)
91120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX3_CLR_REG(n)	(0xCC + (n) * 16)
92120b6fc9SSvatopluk Kraus 
93120b6fc9SSvatopluk Kraus /* Prescaler Register */
94120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PSR_19_2		0x80000000	/* 19.2 MHz */
95120b6fc9SSvatopluk Kraus 
96120b6fc9SSvatopluk Kraus /* GPU Interrupt Routing Register */
97120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GIRR_IRQ_CORE(n)	(n)
98120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GIRR_FIQ_CORE(n)	((n) << 2)
99120b6fc9SSvatopluk Kraus 
100120b6fc9SSvatopluk Kraus /* PMU Interrupt Routing Register */
101120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PIRR_IRQ_EN_CORE(n)	(1 << (n))
102120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PIRR_FIQ_EN_CORE(n)	(1 << ((n) + 4))
103120b6fc9SSvatopluk Kraus 
104120b6fc9SSvatopluk Kraus /* Timer Config Register */
105120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TCR_IRQ_EN_TIMER(n)	(1 << (n))
106120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TCR_FIQ_EN_TIMER(n)	(1 << ((n) + 4))
107120b6fc9SSvatopluk Kraus 
108120b6fc9SSvatopluk Kraus /* MBOX Config Register */
109120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MCR_IRQ_EN_MBOX(n)	(1 << (n))
110120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MCR_FIQ_EN_MBOX(n)	(1 << ((n) + 4))
111120b6fc9SSvatopluk Kraus 
112120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTPSIRQ_IRQ		0
113120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTPNSIRQ_IRQ		1
114120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTHPIRQ_IRQ		2
115120b6fc9SSvatopluk Kraus #define	BCM_LINTC_CNTVIRQ_IRQ		3
116120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_IRQ		4
117120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX1_IRQ		5
118120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX2_IRQ		6
119120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX3_IRQ		7
120120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GPU_IRQ		8
121120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_IRQ		9
122120b6fc9SSvatopluk Kraus #define	BCM_LINTC_AXI_IRQ		10
123120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LTIMER_IRQ		11
124120b6fc9SSvatopluk Kraus 
125120b6fc9SSvatopluk Kraus #define	BCM_LINTC_NIRQS			12
126120b6fc9SSvatopluk Kraus 
127120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER0_IRQ		BCM_LINTC_CNTPSIRQ_IRQ
128120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER1_IRQ		BCM_LINTC_CNTPNSIRQ_IRQ
129120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER2_IRQ		BCM_LINTC_CNTHPIRQ_IRQ
130120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER3_IRQ		BCM_LINTC_CNTVIRQ_IRQ
131120b6fc9SSvatopluk Kraus 
132120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER0_IRQ_MASK	(1 << BCM_LINTC_TIMER0_IRQ)
133120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER1_IRQ_MASK	(1 << BCM_LINTC_TIMER1_IRQ)
134120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER2_IRQ_MASK	(1 << BCM_LINTC_TIMER2_IRQ)
135120b6fc9SSvatopluk Kraus #define	BCM_LINTC_TIMER3_IRQ_MASK	(1 << BCM_LINTC_TIMER3_IRQ)
136120b6fc9SSvatopluk Kraus #define	BCM_LINTC_MBOX0_IRQ_MASK	(1 << BCM_LINTC_MBOX0_IRQ)
137120b6fc9SSvatopluk Kraus #define	BCM_LINTC_GPU_IRQ_MASK		(1 << BCM_LINTC_GPU_IRQ)
138120b6fc9SSvatopluk Kraus #define	BCM_LINTC_PMU_IRQ_MASK		(1 << BCM_LINTC_PMU_IRQ)
139120b6fc9SSvatopluk Kraus 
140120b6fc9SSvatopluk Kraus #define	BCM_LINTC_UP_PENDING_MASK	\
141120b6fc9SSvatopluk Kraus     (BCM_LINTC_TIMER0_IRQ_MASK |	\
142120b6fc9SSvatopluk Kraus      BCM_LINTC_TIMER1_IRQ_MASK |	\
143120b6fc9SSvatopluk Kraus      BCM_LINTC_TIMER2_IRQ_MASK |	\
144120b6fc9SSvatopluk Kraus      BCM_LINTC_TIMER3_IRQ_MASK |	\
145120b6fc9SSvatopluk Kraus      BCM_LINTC_GPU_IRQ_MASK |		\
146120b6fc9SSvatopluk Kraus      BCM_LINTC_PMU_IRQ_MASK)
147120b6fc9SSvatopluk Kraus 
148120b6fc9SSvatopluk Kraus #define	BCM_LINTC_SMP_PENDING_MASK	\
149120b6fc9SSvatopluk Kraus     (BCM_LINTC_UP_PENDING_MASK |	\
150120b6fc9SSvatopluk Kraus      BCM_LINTC_MBOX0_IRQ_MASK)
151120b6fc9SSvatopluk Kraus 
152120b6fc9SSvatopluk Kraus #ifdef SMP
153120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK		BCM_LINTC_SMP_PENDING_MASK
154120b6fc9SSvatopluk Kraus #else
155120b6fc9SSvatopluk Kraus #define BCM_LINTC_PENDING_MASK		BCM_LINTC_UP_PENDING_MASK
156120b6fc9SSvatopluk Kraus #endif
157120b6fc9SSvatopluk Kraus 
158120b6fc9SSvatopluk Kraus struct bcm_lintc_irqsrc {
159120b6fc9SSvatopluk Kraus 	struct intr_irqsrc	bli_isrc;
160120b6fc9SSvatopluk Kraus 	u_int			bli_irq;
161120b6fc9SSvatopluk Kraus 	union {
162120b6fc9SSvatopluk Kraus 		u_int		bli_mask;	/* for timers */
163120b6fc9SSvatopluk Kraus 		u_int		bli_value;	/* for GPU */
164120b6fc9SSvatopluk Kraus 	};
165120b6fc9SSvatopluk Kraus };
166120b6fc9SSvatopluk Kraus 
167120b6fc9SSvatopluk Kraus struct bcm_lintc_softc {
168120b6fc9SSvatopluk Kraus 	device_t		bls_dev;
169120b6fc9SSvatopluk Kraus 	struct mtx		bls_mtx;
170120b6fc9SSvatopluk Kraus 	struct resource *	bls_mem;
171120b6fc9SSvatopluk Kraus 	bus_space_tag_t		bls_bst;
172120b6fc9SSvatopluk Kraus 	bus_space_handle_t	bls_bsh;
173120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc	bls_isrcs[BCM_LINTC_NIRQS];
174120b6fc9SSvatopluk Kraus };
175120b6fc9SSvatopluk Kraus 
176120b6fc9SSvatopluk Kraus static struct bcm_lintc_softc *bcm_lintc_sc;
177120b6fc9SSvatopluk Kraus 
178120b6fc9SSvatopluk Kraus #ifdef SMP
179120b6fc9SSvatopluk Kraus #define BCM_LINTC_NIPIS		32	/* only mailbox 0 is used for IPI */
180120b6fc9SSvatopluk Kraus CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
181120b6fc9SSvatopluk Kraus #endif
182120b6fc9SSvatopluk Kraus 
183120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LOCK(sc)		mtx_lock_spin(&(sc)->bls_mtx)
184120b6fc9SSvatopluk Kraus #define	BCM_LINTC_UNLOCK(sc)		mtx_unlock_spin(&(sc)->bls_mtx)
185120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LOCK_INIT(sc)		mtx_init(&(sc)->bls_mtx,	\
186120b6fc9SSvatopluk Kraus     device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
187120b6fc9SSvatopluk Kraus #define	BCM_LINTC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->bls_mtx)
188120b6fc9SSvatopluk Kraus 
189120b6fc9SSvatopluk Kraus #define	bcm_lintc_read_4(sc, reg)		\
190120b6fc9SSvatopluk Kraus     bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
191120b6fc9SSvatopluk Kraus #define	bcm_lintc_write_4(sc, reg, val)		\
192120b6fc9SSvatopluk Kraus     bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
193120b6fc9SSvatopluk Kraus 
194120b6fc9SSvatopluk Kraus static inline void
195120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
196120b6fc9SSvatopluk Kraus     uint32_t mask)
197120b6fc9SSvatopluk Kraus {
198120b6fc9SSvatopluk Kraus 
199120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
200120b6fc9SSvatopluk Kraus }
201120b6fc9SSvatopluk Kraus 
202120b6fc9SSvatopluk Kraus static inline void
203120b6fc9SSvatopluk Kraus bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
204120b6fc9SSvatopluk Kraus     uint32_t mask)
205120b6fc9SSvatopluk Kraus {
206120b6fc9SSvatopluk Kraus 
207120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
208120b6fc9SSvatopluk Kraus }
209120b6fc9SSvatopluk Kraus 
210120b6fc9SSvatopluk Kraus static void
211120b6fc9SSvatopluk Kraus bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
212120b6fc9SSvatopluk Kraus {
213120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
214120b6fc9SSvatopluk Kraus 	uint32_t cpu;
215120b6fc9SSvatopluk Kraus 
216120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
217120b6fc9SSvatopluk Kraus 
218120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
219120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
220120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
221120b6fc9SSvatopluk Kraus 			bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
222120b6fc9SSvatopluk Kraus 			    bli->bli_mask);
223120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
224120b6fc9SSvatopluk Kraus }
225120b6fc9SSvatopluk Kraus 
226120b6fc9SSvatopluk Kraus static void
227120b6fc9SSvatopluk Kraus bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
228120b6fc9SSvatopluk Kraus {
229120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
230120b6fc9SSvatopluk Kraus 	uint32_t cpu;
231120b6fc9SSvatopluk Kraus 
232120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
233120b6fc9SSvatopluk Kraus 
234120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
235120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
236120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
237120b6fc9SSvatopluk Kraus 			bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
238120b6fc9SSvatopluk Kraus 			    bli->bli_mask);
239120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
240120b6fc9SSvatopluk Kraus }
241120b6fc9SSvatopluk Kraus 
242120b6fc9SSvatopluk Kraus static inline void
243120b6fc9SSvatopluk Kraus bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
244120b6fc9SSvatopluk Kraus {
245120b6fc9SSvatopluk Kraus 
246120b6fc9SSvatopluk Kraus 	/* It's accessed just and only by one core. */
247120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
248120b6fc9SSvatopluk Kraus }
249120b6fc9SSvatopluk Kraus 
250120b6fc9SSvatopluk Kraus static inline void
251120b6fc9SSvatopluk Kraus bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
252120b6fc9SSvatopluk Kraus {
253120b6fc9SSvatopluk Kraus 
254120b6fc9SSvatopluk Kraus 	/* It's accessed just and only by one core. */
255120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
256120b6fc9SSvatopluk Kraus }
257120b6fc9SSvatopluk Kraus 
258120b6fc9SSvatopluk Kraus static inline void
259120b6fc9SSvatopluk Kraus bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
260120b6fc9SSvatopluk Kraus {
261120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
262120b6fc9SSvatopluk Kraus 	uint32_t cpu, mask;
263120b6fc9SSvatopluk Kraus 
264120b6fc9SSvatopluk Kraus 	mask = 0;
265120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
266120b6fc9SSvatopluk Kraus 
267120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
268120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
269120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
270120b6fc9SSvatopluk Kraus 			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
271120b6fc9SSvatopluk Kraus 	/* Write-clear register. */
272120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
273120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
274120b6fc9SSvatopluk Kraus }
275120b6fc9SSvatopluk Kraus 
276120b6fc9SSvatopluk Kraus static inline void
277120b6fc9SSvatopluk Kraus bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
278120b6fc9SSvatopluk Kraus {
279120b6fc9SSvatopluk Kraus 	cpuset_t *cpus;
280120b6fc9SSvatopluk Kraus 	uint32_t cpu, mask;
281120b6fc9SSvatopluk Kraus 
282120b6fc9SSvatopluk Kraus 	mask = 0;
283120b6fc9SSvatopluk Kraus 	cpus = &bli->bli_isrc.isrc_cpu;
284120b6fc9SSvatopluk Kraus 
285120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
286120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
287120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, cpus))
288120b6fc9SSvatopluk Kraus 			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
289120b6fc9SSvatopluk Kraus 	/* Write-set register. */
290120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
291120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
292120b6fc9SSvatopluk Kraus }
293120b6fc9SSvatopluk Kraus 
294120b6fc9SSvatopluk Kraus static void
295120b6fc9SSvatopluk Kraus bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
296120b6fc9SSvatopluk Kraus {
297120b6fc9SSvatopluk Kraus 
298120b6fc9SSvatopluk Kraus 	switch (bli->bli_irq) {
299120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER0_IRQ:
300120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER1_IRQ:
301120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER2_IRQ:
302120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER3_IRQ:
303120b6fc9SSvatopluk Kraus 		bcm_lintc_timer_mask(sc, bli);
304120b6fc9SSvatopluk Kraus 		return;
305120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX0_IRQ:
306120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX1_IRQ:
307120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX2_IRQ:
308120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX3_IRQ:
309120b6fc9SSvatopluk Kraus 		return;
310120b6fc9SSvatopluk Kraus 	case BCM_LINTC_GPU_IRQ:
311120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_mask(sc, bli);
312120b6fc9SSvatopluk Kraus 		return;
313120b6fc9SSvatopluk Kraus 	case BCM_LINTC_PMU_IRQ:
314120b6fc9SSvatopluk Kraus 		bcm_lintc_pmu_mask(sc, bli);
315120b6fc9SSvatopluk Kraus 		return;
316120b6fc9SSvatopluk Kraus 	default:
317120b6fc9SSvatopluk Kraus 		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
318120b6fc9SSvatopluk Kraus 	}
319120b6fc9SSvatopluk Kraus }
320120b6fc9SSvatopluk Kraus 
321120b6fc9SSvatopluk Kraus static void
322120b6fc9SSvatopluk Kraus bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
323120b6fc9SSvatopluk Kraus {
324120b6fc9SSvatopluk Kraus 
325120b6fc9SSvatopluk Kraus 	switch (bli->bli_irq) {
326120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER0_IRQ:
327120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER1_IRQ:
328120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER2_IRQ:
329120b6fc9SSvatopluk Kraus 	case BCM_LINTC_TIMER3_IRQ:
330120b6fc9SSvatopluk Kraus 		bcm_lintc_timer_unmask(sc, bli);
331120b6fc9SSvatopluk Kraus 		return;
332120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX0_IRQ:
333120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX1_IRQ:
334120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX2_IRQ:
335120b6fc9SSvatopluk Kraus 	case BCM_LINTC_MBOX3_IRQ:
336120b6fc9SSvatopluk Kraus 		return;
337120b6fc9SSvatopluk Kraus 	case BCM_LINTC_GPU_IRQ:
338120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_unmask(sc, bli);
339120b6fc9SSvatopluk Kraus 		return;
340120b6fc9SSvatopluk Kraus 	case BCM_LINTC_PMU_IRQ:
341120b6fc9SSvatopluk Kraus 		bcm_lintc_pmu_unmask(sc, bli);
342120b6fc9SSvatopluk Kraus 		return;
343120b6fc9SSvatopluk Kraus 	default:
344120b6fc9SSvatopluk Kraus 		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
345120b6fc9SSvatopluk Kraus 	}
346120b6fc9SSvatopluk Kraus }
347120b6fc9SSvatopluk Kraus 
348120b6fc9SSvatopluk Kraus #ifdef SMP
349120b6fc9SSvatopluk Kraus static inline void
350120b6fc9SSvatopluk Kraus bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
351120b6fc9SSvatopluk Kraus {
352120b6fc9SSvatopluk Kraus 	u_int cpu;
353120b6fc9SSvatopluk Kraus 	uint32_t mask;
354120b6fc9SSvatopluk Kraus 
355120b6fc9SSvatopluk Kraus 	mask = 1 << ipi;
356120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < mp_ncpus; cpu++)
357120b6fc9SSvatopluk Kraus 		if (CPU_ISSET(cpu, &cpus))
358120b6fc9SSvatopluk Kraus 			bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
359120b6fc9SSvatopluk Kraus 			    mask);
360120b6fc9SSvatopluk Kraus }
361120b6fc9SSvatopluk Kraus 
362120b6fc9SSvatopluk Kraus static inline void
363120b6fc9SSvatopluk Kraus bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
364120b6fc9SSvatopluk Kraus     struct trapframe *tf)
365120b6fc9SSvatopluk Kraus {
366120b6fc9SSvatopluk Kraus 	u_int ipi;
367120b6fc9SSvatopluk Kraus 	uint32_t mask;
368120b6fc9SSvatopluk Kraus 
369120b6fc9SSvatopluk Kraus 	mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
370120b6fc9SSvatopluk Kraus 	if (mask == 0) {
371120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Spurious ipi detected\n");
372120b6fc9SSvatopluk Kraus 		return;
373120b6fc9SSvatopluk Kraus 	}
374120b6fc9SSvatopluk Kraus 
375120b6fc9SSvatopluk Kraus 	for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
376120b6fc9SSvatopluk Kraus 		if ((mask & 0x01) == 0)
377120b6fc9SSvatopluk Kraus 			continue;
378120b6fc9SSvatopluk Kraus 		/*
379120b6fc9SSvatopluk Kraus 		 * Clear an IPI before dispatching to not miss anyone
380120b6fc9SSvatopluk Kraus 		 * and make sure that it's observed by everybody.
381120b6fc9SSvatopluk Kraus 		 */
382120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
383120b6fc9SSvatopluk Kraus 		dsb();
384120b6fc9SSvatopluk Kraus 		intr_ipi_dispatch(ipi, tf);
385120b6fc9SSvatopluk Kraus 	}
386120b6fc9SSvatopluk Kraus }
387120b6fc9SSvatopluk Kraus #endif
388120b6fc9SSvatopluk Kraus 
389120b6fc9SSvatopluk Kraus static inline void
390120b6fc9SSvatopluk Kraus bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
391120b6fc9SSvatopluk Kraus     struct trapframe *tf)
392120b6fc9SSvatopluk Kraus {
393120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli;
394120b6fc9SSvatopluk Kraus 
395120b6fc9SSvatopluk Kraus 	bli = &sc->bls_isrcs[irq];
396120b6fc9SSvatopluk Kraus 	if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
397120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
398120b6fc9SSvatopluk Kraus }
399120b6fc9SSvatopluk Kraus 
400120b6fc9SSvatopluk Kraus static int
401120b6fc9SSvatopluk Kraus bcm_lintc_intr(void *arg)
402120b6fc9SSvatopluk Kraus {
403120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
404120b6fc9SSvatopluk Kraus 	u_int cpu;
405120b6fc9SSvatopluk Kraus 	uint32_t num, reg;
406120b6fc9SSvatopluk Kraus 	struct trapframe *tf;
407120b6fc9SSvatopluk Kraus 
408120b6fc9SSvatopluk Kraus 	sc = arg;
409120b6fc9SSvatopluk Kraus 	cpu = PCPU_GET(cpuid);
410120b6fc9SSvatopluk Kraus 	tf = curthread->td_intr_frame;
411120b6fc9SSvatopluk Kraus 
412120b6fc9SSvatopluk Kraus 	for (num = 0; ; num++) {
413120b6fc9SSvatopluk Kraus 		reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
414120b6fc9SSvatopluk Kraus 		if ((reg & BCM_LINTC_PENDING_MASK) == 0)
415120b6fc9SSvatopluk Kraus 			break;
416120b6fc9SSvatopluk Kraus #ifdef SMP
417120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
418120b6fc9SSvatopluk Kraus 			bcm_lintc_ipi_dispatch(sc, cpu, tf);
419120b6fc9SSvatopluk Kraus #endif
420120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
421120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
422120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
423120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
424120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
425120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
426120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
427120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
428120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_GPU_IRQ_MASK)
429120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
430120b6fc9SSvatopluk Kraus 		if (reg & BCM_LINTC_PMU_IRQ_MASK)
431120b6fc9SSvatopluk Kraus 			bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
432120b6fc9SSvatopluk Kraus 
433120b6fc9SSvatopluk Kraus 		arm_irq_memory_barrier(0); /* XXX */
434120b6fc9SSvatopluk Kraus 	}
435120b6fc9SSvatopluk Kraus 	reg &= ~BCM_LINTC_PENDING_MASK;
436120b6fc9SSvatopluk Kraus 	if (reg != 0)
437120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
438120b6fc9SSvatopluk Kraus 	else if (num == 0)
439120b6fc9SSvatopluk Kraus 		device_printf(sc->bls_dev, "Spurious interrupt detected\n");
440120b6fc9SSvatopluk Kraus 
441120b6fc9SSvatopluk Kraus 	return (FILTER_HANDLED);
442120b6fc9SSvatopluk Kraus }
443120b6fc9SSvatopluk Kraus 
444120b6fc9SSvatopluk Kraus static void
445120b6fc9SSvatopluk Kraus bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
446120b6fc9SSvatopluk Kraus {
447120b6fc9SSvatopluk Kraus 
448120b6fc9SSvatopluk Kraus 	bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
449120b6fc9SSvatopluk Kraus }
450120b6fc9SSvatopluk Kraus 
451120b6fc9SSvatopluk Kraus static void
452120b6fc9SSvatopluk Kraus bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
453120b6fc9SSvatopluk Kraus {
454120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
455120b6fc9SSvatopluk Kraus 
456120b6fc9SSvatopluk Kraus 	arm_irq_memory_barrier(bli->bli_irq);
457120b6fc9SSvatopluk Kraus 	bcm_lintc_unmask(device_get_softc(dev), bli);
458120b6fc9SSvatopluk Kraus }
459120b6fc9SSvatopluk Kraus 
460120b6fc9SSvatopluk Kraus static int
461120b6fc9SSvatopluk Kraus bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
462120b6fc9SSvatopluk Kraus     struct intr_irqsrc **isrcp)
463120b6fc9SSvatopluk Kraus {
464cd642c88SSvatopluk Kraus 	struct intr_map_data_fdt *daf;
465120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
466120b6fc9SSvatopluk Kraus 
467120b6fc9SSvatopluk Kraus 	if (data->type != INTR_MAP_DATA_FDT)
468120b6fc9SSvatopluk Kraus 		return (ENOTSUP);
469cd642c88SSvatopluk Kraus 
470cd642c88SSvatopluk Kraus 	daf = (struct intr_map_data_fdt *)data;
471cd642c88SSvatopluk Kraus 	if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS)
472120b6fc9SSvatopluk Kraus 		return (EINVAL);
473120b6fc9SSvatopluk Kraus 
474120b6fc9SSvatopluk Kraus 	sc = device_get_softc(dev);
475cd642c88SSvatopluk Kraus 	*isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc;
476120b6fc9SSvatopluk Kraus 	return (0);
477120b6fc9SSvatopluk Kraus }
478120b6fc9SSvatopluk Kraus 
479120b6fc9SSvatopluk Kraus static void
480120b6fc9SSvatopluk Kraus bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
481120b6fc9SSvatopluk Kraus {
482120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
483120b6fc9SSvatopluk Kraus 
484120b6fc9SSvatopluk Kraus 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
485120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_mask(device_get_softc(dev), bli);
486120b6fc9SSvatopluk Kraus 	else {
487120b6fc9SSvatopluk Kraus 		/*
488120b6fc9SSvatopluk Kraus 		 * Handler for PPI interrupt does not make sense much unless
489120b6fc9SSvatopluk Kraus 		 * there is one bound ithread for each core for it. Thus the
490120b6fc9SSvatopluk Kraus 		 * interrupt can be masked on current core only while ithread
491120b6fc9SSvatopluk Kraus 		 * bounded to this core ensures unmasking on the same core.
492120b6fc9SSvatopluk Kraus 		 */
493120b6fc9SSvatopluk Kraus 		panic ("%s: handlers are not supported", __func__);
494120b6fc9SSvatopluk Kraus 	}
495120b6fc9SSvatopluk Kraus }
496120b6fc9SSvatopluk Kraus 
497120b6fc9SSvatopluk Kraus static void
498120b6fc9SSvatopluk Kraus bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
499120b6fc9SSvatopluk Kraus {
500120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
501120b6fc9SSvatopluk Kraus 
502120b6fc9SSvatopluk Kraus 	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
503120b6fc9SSvatopluk Kraus 		bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
504120b6fc9SSvatopluk Kraus 	else {
505120b6fc9SSvatopluk Kraus 		/* See comment in bcm_lintc_pre_ithread(). */
506120b6fc9SSvatopluk Kraus 		panic ("%s: handlers are not supported", __func__);
507120b6fc9SSvatopluk Kraus 	}
508120b6fc9SSvatopluk Kraus }
509120b6fc9SSvatopluk Kraus 
510120b6fc9SSvatopluk Kraus static void
511120b6fc9SSvatopluk Kraus bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
512120b6fc9SSvatopluk Kraus {
513120b6fc9SSvatopluk Kraus }
514120b6fc9SSvatopluk Kraus 
515120b6fc9SSvatopluk Kraus static int
516120b6fc9SSvatopluk Kraus bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
517120b6fc9SSvatopluk Kraus     struct resource *res, struct intr_map_data *data)
518120b6fc9SSvatopluk Kraus {
519120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
520120b6fc9SSvatopluk Kraus 
521120b6fc9SSvatopluk Kraus 	if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
522120b6fc9SSvatopluk Kraus 		sc = device_get_softc(dev);
523120b6fc9SSvatopluk Kraus 		BCM_LINTC_LOCK(sc);
524120b6fc9SSvatopluk Kraus 		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
525120b6fc9SSvatopluk Kraus 		BCM_LINTC_UNLOCK(sc);
526120b6fc9SSvatopluk Kraus 	}
527120b6fc9SSvatopluk Kraus 	return (0);
528120b6fc9SSvatopluk Kraus }
529120b6fc9SSvatopluk Kraus 
530120b6fc9SSvatopluk Kraus #ifdef SMP
531120b6fc9SSvatopluk Kraus static void
532120b6fc9SSvatopluk Kraus bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
533120b6fc9SSvatopluk Kraus     uint32_t reg, uint32_t mask)
534120b6fc9SSvatopluk Kraus {
535120b6fc9SSvatopluk Kraus 
5365b613c19SSvatopluk Kraus 	if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu))
537120b6fc9SSvatopluk Kraus 		bcm_lintc_rwreg_set(sc, reg, mask);
538120b6fc9SSvatopluk Kraus }
539120b6fc9SSvatopluk Kraus 
540120b6fc9SSvatopluk Kraus static void
541120b6fc9SSvatopluk Kraus bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
542120b6fc9SSvatopluk Kraus {
5435b613c19SSvatopluk Kraus 	struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc;
544120b6fc9SSvatopluk Kraus 
5455b613c19SSvatopluk Kraus 	if (intr_isrc_init_on_cpu(isrc, cpu)) {
546120b6fc9SSvatopluk Kraus 		/* Write-set register. */
547120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
548120b6fc9SSvatopluk Kraus 		    BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
549120b6fc9SSvatopluk Kraus 	}
550120b6fc9SSvatopluk Kraus }
551120b6fc9SSvatopluk Kraus 
552120b6fc9SSvatopluk Kraus static void
553120b6fc9SSvatopluk Kraus bcm_lintc_init_secondary(device_t dev)
554120b6fc9SSvatopluk Kraus {
555120b6fc9SSvatopluk Kraus 	u_int cpu;
556120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
557120b6fc9SSvatopluk Kraus 
558120b6fc9SSvatopluk Kraus 	cpu = PCPU_GET(cpuid);
559120b6fc9SSvatopluk Kraus 	sc = device_get_softc(dev);
560120b6fc9SSvatopluk Kraus 
561120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK(sc);
562120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
563120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
564120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
565120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
566120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
567120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
568120b6fc9SSvatopluk Kraus 	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
569120b6fc9SSvatopluk Kraus 	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
570120b6fc9SSvatopluk Kraus 	bcm_lintc_init_pmu_on_ap(sc, cpu);
571120b6fc9SSvatopluk Kraus 	BCM_LINTC_UNLOCK(sc);
572120b6fc9SSvatopluk Kraus }
573120b6fc9SSvatopluk Kraus 
574120b6fc9SSvatopluk Kraus static void
575120b6fc9SSvatopluk Kraus bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
576120b6fc9SSvatopluk Kraus     u_int ipi)
577120b6fc9SSvatopluk Kraus {
578120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc = device_get_softc(dev);
579120b6fc9SSvatopluk Kraus 
580120b6fc9SSvatopluk Kraus 	KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
581120b6fc9SSvatopluk Kraus 	    ("%s: bad ISRC %p argument", __func__, isrc));
582120b6fc9SSvatopluk Kraus 	bcm_lintc_ipi_write(sc, cpus, ipi);
583120b6fc9SSvatopluk Kraus }
584120b6fc9SSvatopluk Kraus 
585120b6fc9SSvatopluk Kraus static int
586120b6fc9SSvatopluk Kraus bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
587120b6fc9SSvatopluk Kraus {
588120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc = device_get_softc(dev);
589120b6fc9SSvatopluk Kraus 
590120b6fc9SSvatopluk Kraus 	KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
591120b6fc9SSvatopluk Kraus 
592120b6fc9SSvatopluk Kraus 	*isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
593120b6fc9SSvatopluk Kraus 	return (0);
594120b6fc9SSvatopluk Kraus }
595120b6fc9SSvatopluk Kraus #endif
596120b6fc9SSvatopluk Kraus 
597120b6fc9SSvatopluk Kraus static int
598120b6fc9SSvatopluk Kraus bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
599120b6fc9SSvatopluk Kraus {
600120b6fc9SSvatopluk Kraus 	struct bcm_lintc_irqsrc *bisrcs;
601*9346e913SAndrew Turner 	struct intr_pic *pic;
602120b6fc9SSvatopluk Kraus 	int error;
603120b6fc9SSvatopluk Kraus 	u_int flags;
604120b6fc9SSvatopluk Kraus 	uint32_t irq;
605120b6fc9SSvatopluk Kraus 	const char *name;
606120b6fc9SSvatopluk Kraus 	intptr_t xref;
607120b6fc9SSvatopluk Kraus 
608120b6fc9SSvatopluk Kraus 	bisrcs = sc->bls_isrcs;
609120b6fc9SSvatopluk Kraus 	name = device_get_nameunit(sc->bls_dev);
610120b6fc9SSvatopluk Kraus 	for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
611120b6fc9SSvatopluk Kraus 		bisrcs[irq].bli_irq = irq;
612120b6fc9SSvatopluk Kraus 		switch (irq) {
613120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER0_IRQ:
614120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
615120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
616120b6fc9SSvatopluk Kraus 			break;
617120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER1_IRQ:
618120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
619120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
620120b6fc9SSvatopluk Kraus 			break;
621120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER2_IRQ:
622120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
623120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
624120b6fc9SSvatopluk Kraus 			break;
625120b6fc9SSvatopluk Kraus 		case BCM_LINTC_TIMER3_IRQ:
626120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
627120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
628120b6fc9SSvatopluk Kraus 			break;
629120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX0_IRQ:
630120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX1_IRQ:
631120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX2_IRQ:
632120b6fc9SSvatopluk Kraus 		case BCM_LINTC_MBOX3_IRQ:
633120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = 0;	/* not used */
634120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_IPI;
635120b6fc9SSvatopluk Kraus 			break;
636120b6fc9SSvatopluk Kraus 		case BCM_LINTC_GPU_IRQ:
637120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
638120b6fc9SSvatopluk Kraus 			flags = 0;
639120b6fc9SSvatopluk Kraus 			break;
640120b6fc9SSvatopluk Kraus 		case BCM_LINTC_PMU_IRQ:
641120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = 0;	/* not used */
642120b6fc9SSvatopluk Kraus 			flags = INTR_ISRCF_PPI;
643120b6fc9SSvatopluk Kraus 			break;
644120b6fc9SSvatopluk Kraus 		default:
645120b6fc9SSvatopluk Kraus 			bisrcs[irq].bli_value = 0;	/* not used */
646120b6fc9SSvatopluk Kraus 			flags = 0;
647120b6fc9SSvatopluk Kraus 			break;
648120b6fc9SSvatopluk Kraus 		}
649120b6fc9SSvatopluk Kraus 
650120b6fc9SSvatopluk Kraus 		error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
651120b6fc9SSvatopluk Kraus 		    flags, "%s,%u", name, irq);
652120b6fc9SSvatopluk Kraus 		if (error != 0)
653120b6fc9SSvatopluk Kraus 			return (error);
654120b6fc9SSvatopluk Kraus 	}
655120b6fc9SSvatopluk Kraus 
656120b6fc9SSvatopluk Kraus 	xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
657*9346e913SAndrew Turner 	pic = intr_pic_register(sc->bls_dev, xref);
658*9346e913SAndrew Turner 	if (pic == NULL)
659*9346e913SAndrew Turner 		return (ENXIO);
660120b6fc9SSvatopluk Kraus 
661120b6fc9SSvatopluk Kraus 	return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
662120b6fc9SSvatopluk Kraus }
663120b6fc9SSvatopluk Kraus 
664120b6fc9SSvatopluk Kraus static int
665120b6fc9SSvatopluk Kraus bcm_lintc_probe(device_t dev)
666120b6fc9SSvatopluk Kraus {
667120b6fc9SSvatopluk Kraus 
668120b6fc9SSvatopluk Kraus 	if (!ofw_bus_status_okay(dev))
669120b6fc9SSvatopluk Kraus 		return (ENXIO);
670120b6fc9SSvatopluk Kraus 
671120b6fc9SSvatopluk Kraus 	if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
672120b6fc9SSvatopluk Kraus 		return (ENXIO);
673120b6fc9SSvatopluk Kraus 	device_set_desc(dev, "BCM2836 Interrupt Controller");
674120b6fc9SSvatopluk Kraus 	return (BUS_PROBE_DEFAULT);
675120b6fc9SSvatopluk Kraus }
676120b6fc9SSvatopluk Kraus 
677120b6fc9SSvatopluk Kraus static int
678120b6fc9SSvatopluk Kraus bcm_lintc_attach(device_t dev)
679120b6fc9SSvatopluk Kraus {
680120b6fc9SSvatopluk Kraus 	struct bcm_lintc_softc *sc;
681120b6fc9SSvatopluk Kraus 	int cpu, rid;
682120b6fc9SSvatopluk Kraus 
683120b6fc9SSvatopluk Kraus 	sc = device_get_softc(dev);
684120b6fc9SSvatopluk Kraus 
685120b6fc9SSvatopluk Kraus 	sc->bls_dev = dev;
686120b6fc9SSvatopluk Kraus 	if (bcm_lintc_sc != NULL)
687120b6fc9SSvatopluk Kraus 		return (ENXIO);
688120b6fc9SSvatopluk Kraus 
689120b6fc9SSvatopluk Kraus 	rid = 0;
690120b6fc9SSvatopluk Kraus 	sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
691120b6fc9SSvatopluk Kraus 	    RF_ACTIVE);
692120b6fc9SSvatopluk Kraus 	if (sc->bls_mem == NULL) {
693120b6fc9SSvatopluk Kraus 		device_printf(dev, "could not allocate memory resource\n");
694120b6fc9SSvatopluk Kraus 		return (ENXIO);
695120b6fc9SSvatopluk Kraus 	}
696120b6fc9SSvatopluk Kraus 
697120b6fc9SSvatopluk Kraus 	sc->bls_bst = rman_get_bustag(sc->bls_mem);
698120b6fc9SSvatopluk Kraus 	sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
699120b6fc9SSvatopluk Kraus 
700120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
701120b6fc9SSvatopluk Kraus 	bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
702120b6fc9SSvatopluk Kraus 
703120b6fc9SSvatopluk Kraus 	/* Disable all timers on all cores. */
704120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
705120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
706120b6fc9SSvatopluk Kraus 
707120b6fc9SSvatopluk Kraus #ifdef SMP
708120b6fc9SSvatopluk Kraus 	/* Enable mailbox 0 on all cores used for IPI. */
709120b6fc9SSvatopluk Kraus 	for (cpu = 0; cpu < 4; cpu++)
710120b6fc9SSvatopluk Kraus 		bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
711120b6fc9SSvatopluk Kraus 		    BCM_LINTC_MCR_IRQ_EN_MBOX(0));
712120b6fc9SSvatopluk Kraus #endif
713120b6fc9SSvatopluk Kraus 
714120b6fc9SSvatopluk Kraus 	if (bcm_lintc_pic_attach(sc) != 0) {
715120b6fc9SSvatopluk Kraus 		device_printf(dev, "could not attach PIC\n");
716120b6fc9SSvatopluk Kraus 		return (ENXIO);
717120b6fc9SSvatopluk Kraus 	}
718120b6fc9SSvatopluk Kraus 
719120b6fc9SSvatopluk Kraus 	BCM_LINTC_LOCK_INIT(sc);
720120b6fc9SSvatopluk Kraus 	bcm_lintc_sc = sc;
721120b6fc9SSvatopluk Kraus 	return (0);
722120b6fc9SSvatopluk Kraus }
723120b6fc9SSvatopluk Kraus 
724120b6fc9SSvatopluk Kraus static device_method_t bcm_lintc_methods[] = {
725120b6fc9SSvatopluk Kraus 	DEVMETHOD(device_probe,		bcm_lintc_probe),
726120b6fc9SSvatopluk Kraus 	DEVMETHOD(device_attach,	bcm_lintc_attach),
727120b6fc9SSvatopluk Kraus 
728120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_disable_intr,	bcm_lintc_disable_intr),
729120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_enable_intr,	bcm_lintc_enable_intr),
730120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_map_intr,		bcm_lintc_map_intr),
731120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_post_filter,	bcm_lintc_post_filter),
732120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_post_ithread,	bcm_lintc_post_ithread),
733120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_pre_ithread,	bcm_lintc_pre_ithread),
734120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_setup_intr,	bcm_lintc_setup_intr),
735120b6fc9SSvatopluk Kraus #ifdef SMP
736120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_init_secondary,	bcm_lintc_init_secondary),
737120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_ipi_send,		bcm_lintc_ipi_send),
738120b6fc9SSvatopluk Kraus 	DEVMETHOD(pic_ipi_setup,	bcm_lintc_ipi_setup),
739120b6fc9SSvatopluk Kraus #endif
740120b6fc9SSvatopluk Kraus 
741120b6fc9SSvatopluk Kraus 	DEVMETHOD_END
742120b6fc9SSvatopluk Kraus };
743120b6fc9SSvatopluk Kraus 
744120b6fc9SSvatopluk Kraus static driver_t bcm_lintc_driver = {
745120b6fc9SSvatopluk Kraus 	"local_intc",
746120b6fc9SSvatopluk Kraus 	bcm_lintc_methods,
747120b6fc9SSvatopluk Kraus 	sizeof(struct bcm_lintc_softc),
748120b6fc9SSvatopluk Kraus };
749120b6fc9SSvatopluk Kraus 
750120b6fc9SSvatopluk Kraus static devclass_t bcm_lintc_devclass;
751120b6fc9SSvatopluk Kraus 
752120b6fc9SSvatopluk Kraus EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
753120b6fc9SSvatopluk Kraus     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
754120b6fc9SSvatopluk Kraus #else
7554e46a66eSAndrew Turner /*
7564e46a66eSAndrew Turner  * A driver for features of the bcm2836.
7574e46a66eSAndrew Turner  */
7584e46a66eSAndrew Turner 
7594e46a66eSAndrew Turner struct bcm2836_softc {
7604e46a66eSAndrew Turner 	device_t	 sc_dev;
7614e46a66eSAndrew Turner 	struct resource *sc_mem;
7624e46a66eSAndrew Turner };
7634e46a66eSAndrew Turner 
7644e46a66eSAndrew Turner static device_identify_t bcm2836_identify;
7654e46a66eSAndrew Turner static device_probe_t bcm2836_probe;
7664e46a66eSAndrew Turner static device_attach_t bcm2836_attach;
7674e46a66eSAndrew Turner 
7684e46a66eSAndrew Turner struct bcm2836_softc *softc;
7694e46a66eSAndrew Turner 
7704e46a66eSAndrew Turner static void
7714e46a66eSAndrew Turner bcm2836_identify(driver_t *driver, device_t parent)
7724e46a66eSAndrew Turner {
7734e46a66eSAndrew Turner 
7744e46a66eSAndrew Turner 	if (BUS_ADD_CHILD(parent, 0, "bcm2836", -1) == NULL)
7754e46a66eSAndrew Turner 		device_printf(parent, "add child failed\n");
7764e46a66eSAndrew Turner }
7774e46a66eSAndrew Turner 
7784e46a66eSAndrew Turner static int
7794e46a66eSAndrew Turner bcm2836_probe(device_t dev)
7804e46a66eSAndrew Turner {
7814e46a66eSAndrew Turner 
7824e46a66eSAndrew Turner 	if (softc != NULL)
7834e46a66eSAndrew Turner 		return (ENXIO);
7844e46a66eSAndrew Turner 
7854e46a66eSAndrew Turner 	device_set_desc(dev, "Broadcom bcm2836");
7864e46a66eSAndrew Turner 
7874e46a66eSAndrew Turner 	return (BUS_PROBE_DEFAULT);
7884e46a66eSAndrew Turner }
7894e46a66eSAndrew Turner 
7904e46a66eSAndrew Turner static int
7914e46a66eSAndrew Turner bcm2836_attach(device_t dev)
7924e46a66eSAndrew Turner {
7934e46a66eSAndrew Turner 	int i, rid;
7944e46a66eSAndrew Turner 
7954e46a66eSAndrew Turner 	softc = device_get_softc(dev);
7964e46a66eSAndrew Turner 	softc->sc_dev = dev;
7974e46a66eSAndrew Turner 
7984e46a66eSAndrew Turner 	rid = 0;
7994e46a66eSAndrew Turner 	softc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
8004e46a66eSAndrew Turner 	    ARM_LOCAL_BASE, ARM_LOCAL_BASE + ARM_LOCAL_SIZE, ARM_LOCAL_SIZE,
8014e46a66eSAndrew Turner 	    RF_ACTIVE);
8024e46a66eSAndrew Turner 	if (softc->sc_mem == NULL) {
8034e46a66eSAndrew Turner 		device_printf(dev, "could not allocate memory resource\n");
8044e46a66eSAndrew Turner 		return (ENXIO);
8054e46a66eSAndrew Turner 	}
8064e46a66eSAndrew Turner 
8074e46a66eSAndrew Turner 	bus_write_4(softc->sc_mem, ARM_LOCAL_CONTROL, 0);
8084e46a66eSAndrew Turner 	bus_write_4(softc->sc_mem, ARM_LOCAL_PRESCALER, PRESCALER_19_2);
8094e46a66eSAndrew Turner 
8104e46a66eSAndrew Turner 	for (i = 0; i < 4; i++)
8114e46a66eSAndrew Turner 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_TIMER(i), 0);
8124e46a66eSAndrew Turner 
8134e46a66eSAndrew Turner 	for (i = 0; i < 4; i++)
8144e46a66eSAndrew Turner 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(i), 1);
8154e46a66eSAndrew Turner 
8164e46a66eSAndrew Turner 	return (0);
8174e46a66eSAndrew Turner }
8184e46a66eSAndrew Turner 
8194e46a66eSAndrew Turner int
8204e46a66eSAndrew Turner bcm2836_get_next_irq(int last_irq)
8214e46a66eSAndrew Turner {
8224e46a66eSAndrew Turner 	uint32_t reg;
8234e46a66eSAndrew Turner 	int cpu;
8244e46a66eSAndrew Turner 	int irq;
8254e46a66eSAndrew Turner 
8264e46a66eSAndrew Turner 	cpu = PCPU_GET(cpuid);
8274e46a66eSAndrew Turner 
8284e46a66eSAndrew Turner 	reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_PENDING(cpu));
8294e46a66eSAndrew Turner 	reg &= INT_PENDING_MASK;
8304e46a66eSAndrew Turner 	if (reg == 0)
8314e46a66eSAndrew Turner 		return (-1);
8324e46a66eSAndrew Turner 
8334e46a66eSAndrew Turner 	irq = ffs(reg) - 1;
8344e46a66eSAndrew Turner 
8354e46a66eSAndrew Turner 	return (irq);
8364e46a66eSAndrew Turner }
8374e46a66eSAndrew Turner 
8384e46a66eSAndrew Turner void
8394e46a66eSAndrew Turner bcm2836_mask_irq(uintptr_t irq)
8404e46a66eSAndrew Turner {
8414e46a66eSAndrew Turner 	uint32_t reg;
842962940ceSLuiz Otavio O Souza #ifdef SMP
843962940ceSLuiz Otavio O Souza 	int cpu;
844962940ceSLuiz Otavio O Souza #endif
8454e46a66eSAndrew Turner 	int i;
8464e46a66eSAndrew Turner 
847962940ceSLuiz Otavio O Souza 	if (irq < MAILBOX0_IRQ) {
8484e46a66eSAndrew Turner 		for (i = 0; i < 4; i++) {
849962940ceSLuiz Otavio O Souza 			reg = bus_read_4(softc->sc_mem,
850962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i));
8514e46a66eSAndrew Turner 			reg &= ~(1 << irq);
852962940ceSLuiz Otavio O Souza 			bus_write_4(softc->sc_mem,
853962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i), reg);
854962940ceSLuiz Otavio O Souza 		}
855962940ceSLuiz Otavio O Souza #ifdef SMP
856962940ceSLuiz Otavio O Souza 	} else if (irq == MAILBOX0_IRQ) {
857962940ceSLuiz Otavio O Souza 		/* Mailbox 0 for IPI */
858962940ceSLuiz Otavio O Souza 		cpu = PCPU_GET(cpuid);
859962940ceSLuiz Otavio O Souza 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
860962940ceSLuiz Otavio O Souza 		reg &= ~MAILBOX0_IRQEN;
861962940ceSLuiz Otavio O Souza 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
862962940ceSLuiz Otavio O Souza #endif
8634e46a66eSAndrew Turner 	}
8644e46a66eSAndrew Turner }
8654e46a66eSAndrew Turner 
8664e46a66eSAndrew Turner void
8674e46a66eSAndrew Turner bcm2836_unmask_irq(uintptr_t irq)
8684e46a66eSAndrew Turner {
8694e46a66eSAndrew Turner 	uint32_t reg;
870962940ceSLuiz Otavio O Souza #ifdef SMP
871962940ceSLuiz Otavio O Souza 	int cpu;
872962940ceSLuiz Otavio O Souza #endif
8734e46a66eSAndrew Turner 	int i;
8744e46a66eSAndrew Turner 
875962940ceSLuiz Otavio O Souza 	if (irq < MAILBOX0_IRQ) {
8764e46a66eSAndrew Turner 		for (i = 0; i < 4; i++) {
877962940ceSLuiz Otavio O Souza 			reg = bus_read_4(softc->sc_mem,
878962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i));
8794e46a66eSAndrew Turner 			reg |= (1 << irq);
880962940ceSLuiz Otavio O Souza 			bus_write_4(softc->sc_mem,
881962940ceSLuiz Otavio O Souza 			    ARM_LOCAL_INT_TIMER(i), reg);
882962940ceSLuiz Otavio O Souza 		}
883962940ceSLuiz Otavio O Souza #ifdef SMP
884962940ceSLuiz Otavio O Souza 	} else if (irq == MAILBOX0_IRQ) {
885962940ceSLuiz Otavio O Souza 		/* Mailbox 0 for IPI */
886962940ceSLuiz Otavio O Souza 		cpu = PCPU_GET(cpuid);
887962940ceSLuiz Otavio O Souza 		reg = bus_read_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu));
888962940ceSLuiz Otavio O Souza 		reg |= MAILBOX0_IRQEN;
889962940ceSLuiz Otavio O Souza 		bus_write_4(softc->sc_mem, ARM_LOCAL_INT_MAILBOX(cpu), reg);
890962940ceSLuiz Otavio O Souza #endif
8914e46a66eSAndrew Turner 	}
8924e46a66eSAndrew Turner }
8934e46a66eSAndrew Turner 
8944e46a66eSAndrew Turner static device_method_t bcm2836_methods[] = {
8954e46a66eSAndrew Turner 	/* Device interface */
8964e46a66eSAndrew Turner 	DEVMETHOD(device_identify,	bcm2836_identify),
8974e46a66eSAndrew Turner 	DEVMETHOD(device_probe,		bcm2836_probe),
8984e46a66eSAndrew Turner 	DEVMETHOD(device_attach,	bcm2836_attach),
8994e46a66eSAndrew Turner 
9004e46a66eSAndrew Turner 	DEVMETHOD_END
9014e46a66eSAndrew Turner };
9024e46a66eSAndrew Turner 
9034e46a66eSAndrew Turner static devclass_t bcm2836_devclass;
9044e46a66eSAndrew Turner 
9054e46a66eSAndrew Turner static driver_t bcm2836_driver = {
9064e46a66eSAndrew Turner 	"bcm2836",
9074e46a66eSAndrew Turner 	bcm2836_methods,
9084e46a66eSAndrew Turner 	sizeof(struct bcm2836_softc),
9094e46a66eSAndrew Turner };
9104e46a66eSAndrew Turner 
9114e46a66eSAndrew Turner EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
9124e46a66eSAndrew Turner     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
913120b6fc9SSvatopluk Kraus #endif
914