bcm2835_intr.c revision 1.16 1 1.16 skrll /* $NetBSD: bcm2835_intr.c,v 1.16 2019/01/03 10:26:41 skrll Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.8 skrll * Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
5 1.1 skrll * All rights reserved.
6 1.1 skrll *
7 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1 skrll * by Nick Hudson
9 1.1 skrll *
10 1.1 skrll * Redistribution and use in source and binary forms, with or without
11 1.1 skrll * modification, are permitted provided that the following conditions
12 1.1 skrll * are met:
13 1.1 skrll * 1. Redistributions of source code must retain the above copyright
14 1.1 skrll * notice, this list of conditions and the following disclaimer.
15 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 skrll * notice, this list of conditions and the following disclaimer in the
17 1.1 skrll * documentation and/or other materials provided with the distribution.
18 1.1 skrll *
19 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 skrll * POSSIBILITY OF SUCH DAMAGE.
30 1.1 skrll */
31 1.1 skrll
32 1.1 skrll #include <sys/cdefs.h>
33 1.16 skrll __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.16 2019/01/03 10:26:41 skrll Exp $");
34 1.1 skrll
35 1.1 skrll #define _INTR_PRIVATE
36 1.1 skrll
37 1.5 skrll #include "opt_bcm283x.h"
38 1.5 skrll
39 1.1 skrll #include <sys/param.h>
40 1.5 skrll #include <sys/bus.h>
41 1.5 skrll #include <sys/cpu.h>
42 1.5 skrll #include <sys/device.h>
43 1.1 skrll #include <sys/proc.h>
44 1.1 skrll
45 1.15 skrll #include <dev/fdt/fdtvar.h>
46 1.15 skrll
47 1.1 skrll #include <machine/intr.h>
48 1.5 skrll
49 1.5 skrll #include <arm/locore.h>
50 1.1 skrll
51 1.1 skrll #include <arm/pic/picvar.h>
52 1.5 skrll #include <arm/cortex/gtmr_var.h>
53 1.1 skrll
54 1.15 skrll #include <arm/broadcom/bcm2835_intr.h>
55 1.1 skrll #include <arm/broadcom/bcm2835reg.h>
56 1.5 skrll #include <arm/broadcom/bcm2835var.h>
57 1.1 skrll
58 1.15 skrll #include <arm/fdt/arm_fdtvar.h>
59 1.15 skrll
60 1.15 skrll static void bcm2835_irq_handler(void *);
61 1.15 skrll static void bcm2836mp_intr_init(void *, struct cpu_info *);
62 1.15 skrll
63 1.1 skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
64 1.1 skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
65 1.1 skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
66 1.1 skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
67 1.1 skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
68 1.1 skrll size_t);
69 1.1 skrll
70 1.5 skrll static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
71 1.5 skrll static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
72 1.5 skrll static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
73 1.5 skrll static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
74 1.5 skrll static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
75 1.5 skrll size_t);
76 1.5 skrll #ifdef MULTIPROCESSOR
77 1.5 skrll int bcm2836mp_ipi_handler(void *);
78 1.5 skrll static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
79 1.5 skrll static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
80 1.5 skrll #endif
81 1.15 skrll
82 1.15 skrll static int bcm2835_icu_fdt_decode_irq(u_int *);
83 1.15 skrll static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
84 1.15 skrll int (*)(void *), void *);
85 1.15 skrll static void bcm2835_icu_fdt_disestablish(device_t, void *);
86 1.15 skrll static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
87 1.15 skrll
88 1.15 skrll static int bcm2836mp_icu_fdt_decode_irq(u_int *);
89 1.15 skrll static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
90 1.15 skrll int (*)(void *), void *);
91 1.15 skrll static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
92 1.15 skrll static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
93 1.5 skrll
94 1.1 skrll static int bcm2835_icu_match(device_t, cfdata_t, void *);
95 1.1 skrll static void bcm2835_icu_attach(device_t, device_t, void *);
96 1.1 skrll
97 1.15 skrll static void
98 1.15 skrll bcm2835_set_priority(struct pic_softc *pic, int ipl)
99 1.15 skrll {
100 1.15 skrll }
101 1.15 skrll
102 1.1 skrll static struct pic_ops bcm2835_picops = {
103 1.1 skrll .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
104 1.1 skrll .pic_block_irqs = bcm2835_pic_block_irqs,
105 1.1 skrll .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
106 1.1 skrll .pic_establish_irq = bcm2835_pic_establish_irq,
107 1.1 skrll .pic_source_name = bcm2835_pic_source_name,
108 1.15 skrll .pic_set_priority = bcm2835_set_priority,
109 1.1 skrll };
110 1.1 skrll
111 1.1 skrll struct pic_softc bcm2835_pic = {
112 1.1 skrll .pic_ops = &bcm2835_picops,
113 1.1 skrll .pic_maxsources = BCM2835_NIRQ,
114 1.1 skrll .pic_name = "bcm2835 pic",
115 1.1 skrll };
116 1.1 skrll
117 1.5 skrll static struct pic_ops bcm2836mp_picops = {
118 1.5 skrll .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
119 1.5 skrll .pic_block_irqs = bcm2836mp_pic_block_irqs,
120 1.5 skrll .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
121 1.5 skrll .pic_establish_irq = bcm2836mp_pic_establish_irq,
122 1.5 skrll .pic_source_name = bcm2836mp_pic_source_name,
123 1.8 skrll #if defined(MULTIPROCESSOR)
124 1.5 skrll .pic_cpu_init = bcm2836mp_cpu_init,
125 1.5 skrll .pic_ipi_send = bcm2836mp_send_ipi,
126 1.5 skrll #endif
127 1.5 skrll };
128 1.5 skrll
129 1.8 skrll struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
130 1.13 skrll [0 ... BCM2836_NCPUS - 1] = {
131 1.8 skrll .pic_ops = &bcm2836mp_picops,
132 1.8 skrll .pic_maxsources = BCM2836_NIRQPERCPU,
133 1.8 skrll .pic_name = "bcm2836 pic",
134 1.13 skrll }
135 1.5 skrll };
136 1.15 skrll
137 1.15 skrll static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
138 1.15 skrll .establish = bcm2835_icu_fdt_establish,
139 1.15 skrll .disestablish = bcm2835_icu_fdt_disestablish,
140 1.15 skrll .intrstr = bcm2835_icu_fdt_intrstr
141 1.15 skrll };
142 1.15 skrll
143 1.15 skrll static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
144 1.15 skrll .establish = bcm2836mp_icu_fdt_establish,
145 1.15 skrll .disestablish = bcm2836mp_icu_fdt_disestablish,
146 1.15 skrll .intrstr = bcm2836mp_icu_fdt_intrstr
147 1.15 skrll };
148 1.5 skrll
149 1.1 skrll struct bcm2835icu_softc {
150 1.1 skrll device_t sc_dev;
151 1.1 skrll bus_space_tag_t sc_iot;
152 1.1 skrll bus_space_handle_t sc_ioh;
153 1.15 skrll
154 1.15 skrll int sc_phandle;
155 1.1 skrll };
156 1.1 skrll
157 1.15 skrll struct bcm2835icu_softc *bcml1icu_sc;
158 1.1 skrll struct bcm2835icu_softc *bcmicu_sc;
159 1.3 skrll
160 1.1 skrll #define read_bcm2835reg(o) \
161 1.1 skrll bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
162 1.3 skrll
163 1.1 skrll #define write_bcm2835reg(o, v) \
164 1.1 skrll bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
165 1.1 skrll
166 1.1 skrll
167 1.1 skrll #define bcm2835_barrier() \
168 1.1 skrll bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
169 1.1 skrll BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
170 1.3 skrll
171 1.1 skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
172 1.1 skrll "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
173 1.1 skrll "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
174 1.2 jakllsch "(unused 8)", "usb", "(unused 10)", "(unused 11)",
175 1.2 jakllsch "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
176 1.4 skrll "dma0", "dma1", "dma2", "dma3",
177 1.4 skrll "dma4", "dma5", "dma6", "dma7",
178 1.4 skrll "dma8", "dma9", "dma10", "dma11",
179 1.4 skrll "dma12", "aux", "(unused 30)", "(unused 31)",
180 1.1 skrll "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
181 1.1 skrll "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
182 1.1 skrll "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
183 1.1 skrll "(unused 44)", "pwa0", "pwa1", "(unused 47)",
184 1.1 skrll "smi", "gpio[0]", "gpio[1]", "gpio[2]",
185 1.1 skrll "gpio[3]", "i2c", "spi", "pcm",
186 1.12 jmcneill "sdhost", "uart", "(unused 58)", "(unused 59)",
187 1.1 skrll "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
188 1.1 skrll "Timer", "Mailbox", "Doorbell0", "Doorbell1",
189 1.1 skrll "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
190 1.1 skrll };
191 1.1 skrll
192 1.8 skrll static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
193 1.5 skrll "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
194 1.5 skrll "mailbox0", "mailbox1", "mailbox2", "mailbox3",
195 1.5 skrll };
196 1.5 skrll
197 1.5 skrll #define BCM2836_INTBIT_GPUPENDING __BIT(8)
198 1.5 skrll
199 1.1 skrll #define BCM2835_INTBIT_PENDING1 __BIT(8)
200 1.1 skrll #define BCM2835_INTBIT_PENDING2 __BIT(9)
201 1.1 skrll #define BCM2835_INTBIT_ARM __BITS(0,7)
202 1.1 skrll #define BCM2835_INTBIT_GPU0 __BITS(10,14)
203 1.1 skrll #define BCM2835_INTBIT_GPU1 __BITS(15,20)
204 1.1 skrll
205 1.1 skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
206 1.1 skrll bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
207 1.1 skrll
208 1.1 skrll static int
209 1.1 skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
210 1.1 skrll {
211 1.15 skrll const char * const compatible[] = {
212 1.15 skrll "brcm,bcm2708-armctrl-ic",
213 1.15 skrll "brcm,bcm2709-armctrl-ic",
214 1.15 skrll "brcm,bcm2835-armctrl-ic",
215 1.15 skrll "brcm,bcm2836-armctrl-ic",
216 1.15 skrll "brcm,bcm2836-l1-intc",
217 1.15 skrll NULL
218 1.15 skrll };
219 1.15 skrll struct fdt_attach_args * const faa = aux;
220 1.1 skrll
221 1.15 skrll return of_match_compatible(faa->faa_phandle, compatible);
222 1.1 skrll }
223 1.1 skrll
224 1.1 skrll static void
225 1.1 skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
226 1.1 skrll {
227 1.15 skrll struct bcm2835icu_softc * const sc = device_private(self);
228 1.15 skrll struct fdt_attach_args * const faa = aux;
229 1.15 skrll struct fdtbus_interrupt_controller_func *ifuncs;
230 1.15 skrll const int phandle = faa->faa_phandle;
231 1.15 skrll bus_addr_t addr;
232 1.15 skrll bus_size_t size;
233 1.15 skrll bus_space_handle_t ioh;
234 1.15 skrll int error;
235 1.15 skrll
236 1.15 skrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
237 1.15 skrll aprint_error(": couldn't get registers\n");
238 1.15 skrll return;
239 1.15 skrll }
240 1.1 skrll
241 1.1 skrll sc->sc_dev = self;
242 1.15 skrll sc->sc_iot = faa->faa_bst;
243 1.1 skrll
244 1.15 skrll if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
245 1.15 skrll aprint_error(": couldn't map device\n");
246 1.1 skrll return;
247 1.1 skrll }
248 1.1 skrll
249 1.15 skrll sc->sc_ioh = ioh;
250 1.15 skrll sc->sc_phandle = phandle;
251 1.5 skrll
252 1.15 skrll const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
253 1.15 skrll if (of_match_compatible(faa->faa_phandle, local_intc)) {
254 1.8 skrll #if defined(MULTIPROCESSOR)
255 1.15 skrll aprint_normal(": Multiprocessor");
256 1.5 skrll #endif
257 1.15 skrll bcml1icu_sc = sc;
258 1.5 skrll
259 1.15 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh,
260 1.15 skrll BCM2836_LOCAL_CONTROL, 0);
261 1.15 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh,
262 1.15 skrll BCM2836_LOCAL_PRESCALER, 0x80000000);
263 1.15 skrll
264 1.15 skrll ifuncs = &bcm2836mpicu_fdt_funcs;
265 1.15 skrll
266 1.15 skrll bcm2836mp_intr_init(self, curcpu());
267 1.15 skrll arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
268 1.15 skrll } else {
269 1.15 skrll if (bcml1icu_sc == NULL)
270 1.15 skrll arm_fdt_irq_set_handler(bcm2835_irq_handler);
271 1.15 skrll bcmicu_sc = sc;
272 1.15 skrll sc->sc_ioh = ioh;
273 1.15 skrll sc->sc_phandle = phandle;
274 1.15 skrll pic_add(&bcm2835_pic, BCM2835_INT_BASE);
275 1.15 skrll ifuncs = &bcm2835icu_fdt_funcs;
276 1.15 skrll }
277 1.15 skrll
278 1.15 skrll error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
279 1.15 skrll if (error != 0) {
280 1.15 skrll aprint_error(": couldn't register with fdtbus: %d\n", error);
281 1.15 skrll return;
282 1.15 skrll }
283 1.1 skrll aprint_normal("\n");
284 1.1 skrll }
285 1.1 skrll
286 1.15 skrll static void
287 1.1 skrll bcm2835_irq_handler(void *frame)
288 1.1 skrll {
289 1.1 skrll struct cpu_info * const ci = curcpu();
290 1.1 skrll const int oldipl = ci->ci_cpl;
291 1.16 skrll const cpuid_t cpuid = ci->ci_core_id;
292 1.1 skrll const uint32_t oldipl_mask = __BIT(oldipl);
293 1.1 skrll int ipl_mask = 0;
294 1.1 skrll
295 1.1 skrll ci->ci_data.cpu_nintr++;
296 1.1 skrll
297 1.1 skrll bcm2835_barrier();
298 1.8 skrll if (cpuid == 0) {
299 1.8 skrll ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
300 1.8 skrll }
301 1.15 skrll #if defined(SOC_BCM2836)
302 1.8 skrll ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
303 1.5 skrll #endif
304 1.1 skrll
305 1.1 skrll /*
306 1.1 skrll * Record the pending_ipls and deliver them if we can.
307 1.1 skrll */
308 1.1 skrll if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
309 1.1 skrll pic_do_pending_ints(I32_bit, oldipl, frame);
310 1.1 skrll }
311 1.1 skrll
312 1.1 skrll static void
313 1.1 skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
314 1.1 skrll uint32_t irq_mask)
315 1.1 skrll {
316 1.1 skrll
317 1.1 skrll write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
318 1.1 skrll bcm2835_barrier();
319 1.1 skrll }
320 1.1 skrll
321 1.1 skrll static void
322 1.1 skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
323 1.1 skrll uint32_t irq_mask)
324 1.1 skrll {
325 1.1 skrll
326 1.1 skrll write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
327 1.1 skrll bcm2835_barrier();
328 1.1 skrll }
329 1.1 skrll
330 1.1 skrll /*
331 1.1 skrll * Called with interrupts disabled
332 1.1 skrll */
333 1.1 skrll static int
334 1.1 skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
335 1.1 skrll {
336 1.1 skrll int ipl = 0;
337 1.1 skrll uint32_t bpending, gpu0irq, gpu1irq, armirq;
338 1.1 skrll
339 1.1 skrll bcm2835_barrier();
340 1.1 skrll bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
341 1.1 skrll if (bpending == 0)
342 1.1 skrll return 0;
343 1.1 skrll
344 1.1 skrll armirq = bpending & BCM2835_INTBIT_ARM;
345 1.1 skrll gpu0irq = bpending & BCM2835_INTBIT_GPU0;
346 1.1 skrll gpu1irq = bpending & BCM2835_INTBIT_GPU1;
347 1.1 skrll
348 1.1 skrll if (armirq) {
349 1.8 skrll ipl |= pic_mark_pending_sources(pic,
350 1.8 skrll BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
351 1.1 skrll }
352 1.1 skrll
353 1.1 skrll if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
354 1.1 skrll uint32_t pending1;
355 1.3 skrll
356 1.1 skrll pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
357 1.8 skrll ipl |= pic_mark_pending_sources(pic,
358 1.8 skrll BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
359 1.1 skrll }
360 1.1 skrll if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
361 1.1 skrll uint32_t pending2;
362 1.3 skrll
363 1.1 skrll pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
364 1.8 skrll ipl |= pic_mark_pending_sources(pic,
365 1.8 skrll BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
366 1.1 skrll }
367 1.3 skrll
368 1.1 skrll return ipl;
369 1.1 skrll }
370 1.1 skrll
371 1.1 skrll static void
372 1.1 skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
373 1.1 skrll {
374 1.1 skrll
375 1.1 skrll /* Nothing really*/
376 1.1 skrll KASSERT(is->is_irq < BCM2835_NIRQ);
377 1.1 skrll KASSERT(is->is_type == IST_LEVEL);
378 1.1 skrll }
379 1.1 skrll
380 1.1 skrll static void
381 1.1 skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
382 1.1 skrll {
383 1.1 skrll
384 1.1 skrll strlcpy(buf, bcm2835_sources[irq], len);
385 1.1 skrll }
386 1.5 skrll
387 1.15 skrll static int
388 1.15 skrll bcm2835_icu_fdt_decode_irq(u_int *specifier)
389 1.15 skrll {
390 1.15 skrll u_int base;
391 1.15 skrll
392 1.15 skrll if (!specifier)
393 1.15 skrll return -1;
394 1.15 skrll
395 1.15 skrll /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
396 1.15 skrll /* 2nd cell is the irq relative to that bank */
397 1.15 skrll
398 1.15 skrll const u_int bank = be32toh(specifier[0]);
399 1.15 skrll switch (bank) {
400 1.15 skrll case 0:
401 1.15 skrll base = BCM2835_INT_BASICBASE;
402 1.15 skrll break;
403 1.15 skrll case 1:
404 1.15 skrll base = BCM2835_INT_GPU0BASE;
405 1.15 skrll break;
406 1.15 skrll case 2:
407 1.15 skrll base = BCM2835_INT_GPU1BASE;
408 1.15 skrll break;
409 1.15 skrll default:
410 1.15 skrll return -1;
411 1.15 skrll }
412 1.15 skrll const u_int off = be32toh(specifier[1]);
413 1.15 skrll
414 1.15 skrll return base + off;
415 1.15 skrll }
416 1.15 skrll
417 1.15 skrll static void *
418 1.15 skrll bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
419 1.15 skrll int (*func)(void *), void *arg)
420 1.15 skrll {
421 1.15 skrll int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
422 1.15 skrll int irq;
423 1.15 skrll
424 1.15 skrll irq = bcm2835_icu_fdt_decode_irq(specifier);
425 1.15 skrll if (irq == -1)
426 1.15 skrll return NULL;
427 1.5 skrll
428 1.15 skrll return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
429 1.15 skrll }
430 1.15 skrll
431 1.15 skrll static void
432 1.15 skrll bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
433 1.15 skrll {
434 1.15 skrll intr_disestablish(ih);
435 1.15 skrll }
436 1.15 skrll
437 1.15 skrll static bool
438 1.15 skrll bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
439 1.15 skrll {
440 1.15 skrll int irq;
441 1.15 skrll
442 1.15 skrll irq = bcm2835_icu_fdt_decode_irq(specifier);
443 1.15 skrll if (irq == -1)
444 1.15 skrll return false;
445 1.15 skrll
446 1.15 skrll snprintf(buf, buflen, "icu irq %d", irq);
447 1.15 skrll
448 1.15 skrll return true;
449 1.15 skrll }
450 1.5 skrll
451 1.5 skrll #define BCM2836MP_TIMER_IRQS __BITS(3,0)
452 1.5 skrll #define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
453 1.5 skrll
454 1.15 skrll #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
455 1.5 skrll
456 1.5 skrll static void
457 1.5 skrll bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
458 1.5 skrll uint32_t irq_mask)
459 1.5 skrll {
460 1.8 skrll struct cpu_info * const ci = curcpu();
461 1.16 skrll const cpuid_t cpuid = ci->ci_core_id;
462 1.15 skrll const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
463 1.15 skrll const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
464 1.5 skrll
465 1.8 skrll KASSERT(pic == &bcm2836mp_pic[cpuid]);
466 1.8 skrll KASSERT(irqbase == 0);
467 1.5 skrll
468 1.5 skrll if (irq_mask & BCM2836MP_TIMER_IRQS) {
469 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
470 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
471 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
472 1.5 skrll val |= mask;
473 1.15 skrll bus_space_write_4(iot, ioh,
474 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
475 1.5 skrll val);
476 1.15 skrll bus_space_barrier(iot, ioh,
477 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
478 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
479 1.5 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
480 1.10 skrll }
481 1.10 skrll if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
482 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
483 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
484 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
485 1.5 skrll val |= mask;
486 1.15 skrll bus_space_write_4(iot, ioh,
487 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
488 1.5 skrll val);
489 1.15 skrll bus_space_barrier(iot, ioh,
490 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
491 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
492 1.5 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
493 1.5 skrll }
494 1.5 skrll
495 1.5 skrll return;
496 1.5 skrll }
497 1.5 skrll
498 1.5 skrll static void
499 1.5 skrll bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
500 1.5 skrll uint32_t irq_mask)
501 1.5 skrll {
502 1.8 skrll struct cpu_info * const ci = curcpu();
503 1.16 skrll const cpuid_t cpuid = ci->ci_core_id;
504 1.15 skrll const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
505 1.15 skrll const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
506 1.8 skrll
507 1.8 skrll KASSERT(pic == &bcm2836mp_pic[cpuid]);
508 1.8 skrll KASSERT(irqbase == 0);
509 1.5 skrll
510 1.5 skrll if (irq_mask & BCM2836MP_TIMER_IRQS) {
511 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
512 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
513 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
514 1.5 skrll val &= ~mask;
515 1.15 skrll bus_space_write_4(iot, ioh,
516 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
517 1.5 skrll val);
518 1.10 skrll }
519 1.10 skrll if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
520 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
521 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
522 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
523 1.5 skrll val &= ~mask;
524 1.15 skrll bus_space_write_4(iot, ioh,
525 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
526 1.5 skrll val);
527 1.5 skrll }
528 1.5 skrll
529 1.5 skrll bcm2835_barrier();
530 1.5 skrll return;
531 1.5 skrll }
532 1.5 skrll
533 1.5 skrll static int
534 1.5 skrll bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
535 1.5 skrll {
536 1.8 skrll struct cpu_info * const ci = curcpu();
537 1.16 skrll const cpuid_t cpuid = ci->ci_core_id;
538 1.5 skrll uint32_t lpending;
539 1.5 skrll int ipl = 0;
540 1.5 skrll
541 1.8 skrll KASSERT(pic == &bcm2836mp_pic[cpuid]);
542 1.8 skrll
543 1.5 skrll bcm2835_barrier();
544 1.5 skrll
545 1.15 skrll lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
546 1.5 skrll BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
547 1.5 skrll
548 1.5 skrll lpending &= ~BCM2836_INTBIT_GPUPENDING;
549 1.5 skrll if (lpending & BCM2836MP_ALL_IRQS) {
550 1.5 skrll ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
551 1.5 skrll lpending & BCM2836MP_ALL_IRQS);
552 1.5 skrll }
553 1.5 skrll
554 1.5 skrll return ipl;
555 1.5 skrll }
556 1.5 skrll
557 1.5 skrll static void
558 1.5 skrll bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
559 1.5 skrll {
560 1.5 skrll /* Nothing really*/
561 1.5 skrll KASSERT(is->is_irq >= 0);
562 1.8 skrll KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
563 1.8 skrll }
564 1.8 skrll
565 1.8 skrll static void
566 1.8 skrll bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
567 1.8 skrll {
568 1.8 skrll
569 1.8 skrll irq %= BCM2836_NIRQPERCPU;
570 1.8 skrll strlcpy(buf, bcm2836mp_sources[irq], len);
571 1.8 skrll }
572 1.5 skrll
573 1.5 skrll
574 1.15 skrll #if defined(MULTIPROCESSOR)
575 1.8 skrll static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
576 1.8 skrll {
577 1.8 skrll
578 1.8 skrll /* Enable IRQ and not FIQ */
579 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
580 1.16 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
581 1.5 skrll }
582 1.5 skrll
583 1.5 skrll static void
584 1.8 skrll bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
585 1.8 skrll {
586 1.10 skrll KASSERT(pic != NULL);
587 1.10 skrll KASSERT(pic != &bcm2835_pic);
588 1.10 skrll KASSERT(pic->pic_cpus != NULL);
589 1.10 skrll
590 1.8 skrll const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
591 1.8 skrll
592 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
593 1.9 jmcneill BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
594 1.8 skrll }
595 1.8 skrll
596 1.8 skrll int
597 1.8 skrll bcm2836mp_ipi_handler(void *priv)
598 1.8 skrll {
599 1.8 skrll const struct cpu_info *ci = curcpu();
600 1.16 skrll const cpuid_t cpuid = ci->ci_core_id;
601 1.9 jmcneill uint32_t ipimask, bit;
602 1.9 jmcneill
603 1.15 skrll ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
604 1.8 skrll BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
605 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
606 1.15 skrll BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
607 1.8 skrll
608 1.9 jmcneill while ((bit = ffs(ipimask)) > 0) {
609 1.9 jmcneill const u_int ipi = bit - 1;
610 1.9 jmcneill switch (ipi) {
611 1.9 jmcneill case IPI_AST:
612 1.11 skrll pic_ipi_ast(priv);
613 1.11 skrll break;
614 1.9 jmcneill case IPI_NOP:
615 1.11 skrll pic_ipi_nop(priv);
616 1.11 skrll break;
617 1.9 jmcneill #ifdef __HAVE_PREEMPTION
618 1.9 jmcneill case IPI_KPREEMPT:
619 1.11 skrll pic_ipi_kpreempt(priv);
620 1.11 skrll break;
621 1.9 jmcneill #endif
622 1.9 jmcneill case IPI_XCALL:
623 1.9 jmcneill pic_ipi_xcall(priv);
624 1.9 jmcneill break;
625 1.9 jmcneill case IPI_GENERIC:
626 1.9 jmcneill pic_ipi_generic(priv);
627 1.9 jmcneill break;
628 1.9 jmcneill case IPI_SHOOTDOWN:
629 1.9 jmcneill pic_ipi_shootdown(priv);
630 1.9 jmcneill break;
631 1.8 skrll #ifdef DDB
632 1.9 jmcneill case IPI_DDB:
633 1.9 jmcneill pic_ipi_ddb(priv);
634 1.9 jmcneill break;
635 1.8 skrll #endif
636 1.9 jmcneill }
637 1.9 jmcneill ipimask &= ~__BIT(ipi);
638 1.8 skrll }
639 1.8 skrll
640 1.8 skrll return 1;
641 1.8 skrll }
642 1.15 skrll #endif
643 1.8 skrll
644 1.15 skrll static void
645 1.15 skrll bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
646 1.5 skrll {
647 1.16 skrll const cpuid_t cpuid = ci->ci_core_id;
648 1.8 skrll struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
649 1.8 skrll
650 1.15 skrll #if defined(MULTIPROCESSOR)
651 1.8 skrll pic->pic_cpus = ci->ci_kcpuset;
652 1.15 skrll #endif
653 1.8 skrll pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
654 1.8 skrll
655 1.15 skrll #if defined(MULTIPROCESSOR)
656 1.10 skrll intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
657 1.8 skrll IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
658 1.15 skrll #endif
659 1.8 skrll /* clock interrupt will attach with gtmr */
660 1.8 skrll if (cpuid == 0)
661 1.8 skrll return;
662 1.15 skrll #if defined(SOC_BCM2836)
663 1.8 skrll intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
664 1.8 skrll IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
665 1.8 skrll
666 1.15 skrll #endif
667 1.5 skrll }
668 1.8 skrll
669 1.15 skrll static int
670 1.15 skrll bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
671 1.15 skrll {
672 1.15 skrll if (!specifier)
673 1.15 skrll return -1;
674 1.15 skrll return be32toh(specifier[0]) + BCM2836_INT_LOCALBASE;
675 1.15 skrll }
676 1.15 skrll
677 1.15 skrll static void *
678 1.15 skrll bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
679 1.15 skrll int (*func)(void *), void *arg)
680 1.15 skrll {
681 1.15 skrll int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
682 1.15 skrll int irq;
683 1.15 skrll
684 1.15 skrll irq = bcm2836mp_icu_fdt_decode_irq(specifier);
685 1.15 skrll if (irq == -1)
686 1.15 skrll return NULL;
687 1.15 skrll
688 1.15 skrll return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
689 1.15 skrll }
690 1.15 skrll
691 1.15 skrll static void
692 1.15 skrll bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
693 1.15 skrll {
694 1.15 skrll intr_disestablish(ih);
695 1.15 skrll }
696 1.15 skrll
697 1.15 skrll static bool
698 1.15 skrll bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
699 1.15 skrll size_t buflen)
700 1.15 skrll {
701 1.15 skrll int irq;
702 1.15 skrll
703 1.15 skrll irq = bcm2836mp_icu_fdt_decode_irq(specifier);
704 1.15 skrll if (irq == -1)
705 1.15 skrll return false;
706 1.15 skrll
707 1.15 skrll snprintf(buf, buflen, "local_intc irq %d", irq);
708 1.15 skrll
709 1.15 skrll return true;
710 1.15 skrll }
711