bcm2835_intr.c revision 1.38 1 1.38 mlelstv /* $NetBSD: bcm2835_intr.c,v 1.38 2021/03/08 14:22:42 mlelstv Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.25 thorpej * Copyright (c) 2012, 2015, 2019 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.38 mlelstv __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.38 2021/03/08 14:22:42 mlelstv 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.19 skrll #include <sys/kernel.h>
44 1.19 skrll #include <sys/kmem.h>
45 1.1 skrll #include <sys/proc.h>
46 1.1 skrll
47 1.15 skrll #include <dev/fdt/fdtvar.h>
48 1.15 skrll
49 1.1 skrll #include <machine/intr.h>
50 1.5 skrll
51 1.5 skrll #include <arm/locore.h>
52 1.1 skrll
53 1.1 skrll #include <arm/pic/picvar.h>
54 1.5 skrll #include <arm/cortex/gtmr_var.h>
55 1.1 skrll
56 1.15 skrll #include <arm/broadcom/bcm2835_intr.h>
57 1.1 skrll #include <arm/broadcom/bcm2835reg.h>
58 1.5 skrll #include <arm/broadcom/bcm2835var.h>
59 1.1 skrll
60 1.15 skrll #include <arm/fdt/arm_fdtvar.h>
61 1.15 skrll
62 1.15 skrll static void bcm2835_irq_handler(void *);
63 1.15 skrll static void bcm2836mp_intr_init(void *, struct cpu_info *);
64 1.15 skrll
65 1.1 skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
66 1.1 skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
67 1.1 skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
68 1.1 skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
69 1.1 skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
70 1.1 skrll size_t);
71 1.1 skrll
72 1.5 skrll static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
73 1.5 skrll static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
74 1.5 skrll static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
75 1.5 skrll static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
76 1.5 skrll static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
77 1.5 skrll size_t);
78 1.5 skrll #ifdef MULTIPROCESSOR
79 1.5 skrll int bcm2836mp_ipi_handler(void *);
80 1.5 skrll static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
81 1.5 skrll static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
82 1.5 skrll #endif
83 1.15 skrll
84 1.15 skrll static int bcm2835_icu_fdt_decode_irq(u_int *);
85 1.15 skrll static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
86 1.34 jmcneill int (*)(void *), void *, const char *);
87 1.15 skrll static void bcm2835_icu_fdt_disestablish(device_t, void *);
88 1.15 skrll static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
89 1.15 skrll
90 1.25 thorpej static int bcm2835_icu_intr(void *);
91 1.25 thorpej
92 1.15 skrll static int bcm2836mp_icu_fdt_decode_irq(u_int *);
93 1.15 skrll static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
94 1.34 jmcneill int (*)(void *), void *, const char *);
95 1.15 skrll static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
96 1.15 skrll static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
97 1.5 skrll
98 1.1 skrll static int bcm2835_icu_match(device_t, cfdata_t, void *);
99 1.1 skrll static void bcm2835_icu_attach(device_t, device_t, void *);
100 1.1 skrll
101 1.28 skrll static int bcm2835_int_base;
102 1.29 skrll static int bcm2836mp_int_base[BCM2836_NCPUS];
103 1.29 skrll
104 1.29 skrll #define BCM2835_INT_BASE bcm2835_int_base
105 1.29 skrll #define BCM2836_INT_BASECPUN(n) bcm2836mp_int_base[(n)]
106 1.28 skrll
107 1.38 mlelstv #define BCM2836_INT_CNTPSIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTPSIRQ)
108 1.38 mlelstv #define BCM2836_INT_CNTPNSIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTPNSIRQ)
109 1.38 mlelstv #define BCM2836_INT_CNTVIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTVIRQ)
110 1.38 mlelstv #define BCM2836_INT_CNTHPIRQ_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_CNTHPIRQ)
111 1.38 mlelstv #define BCM2836_INT_MAILBOX0_CPUN(n) (BCM2836_INT_BASECPUN(n) + BCM2836_INT_MAILBOX0)
112 1.38 mlelstv
113 1.38 mlelstv /* Periperal Interrupt sources */
114 1.38 mlelstv #define BCM2835_NIRQ 96
115 1.38 mlelstv
116 1.38 mlelstv #define BCM2835_INT_GPU0BASE (BCM2835_INT_BASE + 0)
117 1.38 mlelstv #define BCM2835_INT_TIMER0 (BCM2835_INT_GPU0BASE + 0)
118 1.38 mlelstv #define BCM2835_INT_TIMER1 (BCM2835_INT_GPU0BASE + 1)
119 1.38 mlelstv #define BCM2835_INT_TIMER2 (BCM2835_INT_GPU0BASE + 2)
120 1.38 mlelstv #define BCM2835_INT_TIMER3 (BCM2835_INT_GPU0BASE + 3)
121 1.38 mlelstv #define BCM2835_INT_USB (BCM2835_INT_GPU0BASE + 9)
122 1.38 mlelstv #define BCM2835_INT_DMA0 (BCM2835_INT_GPU0BASE + 16)
123 1.38 mlelstv #define BCM2835_INT_DMA2 (BCM2835_INT_GPU0BASE + 18)
124 1.38 mlelstv #define BCM2835_INT_DMA3 (BCM2835_INT_GPU0BASE + 19)
125 1.38 mlelstv #define BCM2835_INT_AUX (BCM2835_INT_GPU0BASE + 29)
126 1.38 mlelstv #define BCM2835_INT_ARM (BCM2835_INT_GPU0BASE + 30)
127 1.38 mlelstv
128 1.38 mlelstv #define BCM2835_INT_GPU1BASE (BCM2835_INT_BASE + 32)
129 1.38 mlelstv #define BCM2835_INT_GPIO0 (BCM2835_INT_GPU1BASE + 17)
130 1.38 mlelstv #define BCM2835_INT_GPIO1 (BCM2835_INT_GPU1BASE + 18)
131 1.38 mlelstv #define BCM2835_INT_GPIO2 (BCM2835_INT_GPU1BASE + 19)
132 1.38 mlelstv #define BCM2835_INT_GPIO3 (BCM2835_INT_GPU1BASE + 20)
133 1.38 mlelstv #define BCM2835_INT_BSC (BCM2835_INT_GPU1BASE + 21)
134 1.38 mlelstv #define BCM2835_INT_SPI0 (BCM2835_INT_GPU1BASE + 22)
135 1.38 mlelstv #define BCM2835_INT_PCM (BCM2835_INT_GPU1BASE + 23)
136 1.38 mlelstv #define BCM2835_INT_SDHOST (BCM2835_INT_GPU1BASE + 24)
137 1.38 mlelstv #define BCM2835_INT_UART0 (BCM2835_INT_GPU1BASE + 25)
138 1.38 mlelstv #define BCM2835_INT_EMMC (BCM2835_INT_GPU1BASE + 30)
139 1.38 mlelstv
140 1.38 mlelstv #define BCM2835_INT_BASICBASE (BCM2835_INT_BASE + 64)
141 1.38 mlelstv #define BCM2835_INT_ARMTIMER (BCM2835_INT_BASICBASE + 0)
142 1.38 mlelstv #define BCM2835_INT_ARMMAILBOX (BCM2835_INT_BASICBASE + 1)
143 1.38 mlelstv #define BCM2835_INT_ARMDOORBELL0 (BCM2835_INT_BASICBASE + 2)
144 1.38 mlelstv #define BCM2835_INT_ARMDOORBELL1 (BCM2835_INT_BASICBASE + 3)
145 1.38 mlelstv #define BCM2835_INT_GPU0HALTED (BCM2835_INT_BASICBASE + 4)
146 1.38 mlelstv #define BCM2835_INT_GPU1HALTED (BCM2835_INT_BASICBASE + 5)
147 1.38 mlelstv #define BCM2835_INT_ILLEGALTYPE0 (BCM2835_INT_BASICBASE + 6)
148 1.38 mlelstv #define BCM2835_INT_ILLEGALTYPE1 (BCM2835_INT_BASICBASE + 7)
149 1.38 mlelstv
150 1.15 skrll static void
151 1.15 skrll bcm2835_set_priority(struct pic_softc *pic, int ipl)
152 1.15 skrll {
153 1.15 skrll }
154 1.15 skrll
155 1.1 skrll static struct pic_ops bcm2835_picops = {
156 1.1 skrll .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
157 1.1 skrll .pic_block_irqs = bcm2835_pic_block_irqs,
158 1.1 skrll .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
159 1.1 skrll .pic_establish_irq = bcm2835_pic_establish_irq,
160 1.1 skrll .pic_source_name = bcm2835_pic_source_name,
161 1.15 skrll .pic_set_priority = bcm2835_set_priority,
162 1.1 skrll };
163 1.1 skrll
164 1.18 skrll static struct pic_softc bcm2835_pic = {
165 1.1 skrll .pic_ops = &bcm2835_picops,
166 1.1 skrll .pic_maxsources = BCM2835_NIRQ,
167 1.1 skrll .pic_name = "bcm2835 pic",
168 1.1 skrll };
169 1.1 skrll
170 1.5 skrll static struct pic_ops bcm2836mp_picops = {
171 1.5 skrll .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
172 1.5 skrll .pic_block_irqs = bcm2836mp_pic_block_irqs,
173 1.5 skrll .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
174 1.5 skrll .pic_establish_irq = bcm2836mp_pic_establish_irq,
175 1.5 skrll .pic_source_name = bcm2836mp_pic_source_name,
176 1.8 skrll #if defined(MULTIPROCESSOR)
177 1.5 skrll .pic_cpu_init = bcm2836mp_cpu_init,
178 1.5 skrll .pic_ipi_send = bcm2836mp_send_ipi,
179 1.5 skrll #endif
180 1.5 skrll };
181 1.5 skrll
182 1.18 skrll static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
183 1.13 skrll [0 ... BCM2836_NCPUS - 1] = {
184 1.8 skrll .pic_ops = &bcm2836mp_picops,
185 1.8 skrll .pic_maxsources = BCM2836_NIRQPERCPU,
186 1.8 skrll .pic_name = "bcm2836 pic",
187 1.13 skrll }
188 1.5 skrll };
189 1.15 skrll
190 1.15 skrll static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
191 1.15 skrll .establish = bcm2835_icu_fdt_establish,
192 1.15 skrll .disestablish = bcm2835_icu_fdt_disestablish,
193 1.15 skrll .intrstr = bcm2835_icu_fdt_intrstr
194 1.15 skrll };
195 1.15 skrll
196 1.15 skrll static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
197 1.15 skrll .establish = bcm2836mp_icu_fdt_establish,
198 1.15 skrll .disestablish = bcm2836mp_icu_fdt_disestablish,
199 1.15 skrll .intrstr = bcm2836mp_icu_fdt_intrstr
200 1.15 skrll };
201 1.5 skrll
202 1.19 skrll struct bcm2836mp_interrupt {
203 1.19 skrll bool bi_done;
204 1.19 skrll TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
205 1.19 skrll int bi_irq;
206 1.19 skrll int bi_ipl;
207 1.19 skrll int bi_flags;
208 1.19 skrll int (*bi_func)(void *);
209 1.19 skrll void *bi_arg;
210 1.19 skrll void *bi_ihs[BCM2836_NCPUS];
211 1.19 skrll };
212 1.19 skrll
213 1.19 skrll static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
214 1.19 skrll TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
215 1.19 skrll
216 1.25 thorpej struct bcm2835icu_irqhandler;
217 1.25 thorpej struct bcm2835icu_irq;
218 1.25 thorpej struct bcm2835icu_softc;
219 1.25 thorpej
220 1.25 thorpej struct bcm2835icu_irqhandler {
221 1.25 thorpej struct bcm2835icu_irq *ih_irq;
222 1.25 thorpej int (*ih_fn)(void *);
223 1.25 thorpej void *ih_arg;
224 1.25 thorpej TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
225 1.25 thorpej };
226 1.25 thorpej
227 1.25 thorpej struct bcm2835icu_irq {
228 1.25 thorpej struct bcm2835icu_softc *intr_sc;
229 1.25 thorpej void *intr_ih;
230 1.25 thorpej void *intr_arg;
231 1.25 thorpej int intr_refcnt;
232 1.25 thorpej int intr_ipl;
233 1.25 thorpej int intr_irq;
234 1.25 thorpej int intr_mpsafe;
235 1.25 thorpej TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
236 1.25 thorpej };
237 1.25 thorpej
238 1.1 skrll struct bcm2835icu_softc {
239 1.1 skrll device_t sc_dev;
240 1.1 skrll bus_space_tag_t sc_iot;
241 1.1 skrll bus_space_handle_t sc_ioh;
242 1.15 skrll
243 1.25 thorpej struct bcm2835icu_irq *sc_irq[BCM2835_NIRQ];
244 1.25 thorpej
245 1.15 skrll int sc_phandle;
246 1.1 skrll };
247 1.1 skrll
248 1.23 skrll static struct bcm2835icu_softc *bcml1icu_sc;
249 1.23 skrll static struct bcm2835icu_softc *bcmicu_sc;
250 1.3 skrll
251 1.1 skrll #define read_bcm2835reg(o) \
252 1.1 skrll bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
253 1.3 skrll
254 1.1 skrll #define write_bcm2835reg(o, v) \
255 1.1 skrll bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
256 1.1 skrll
257 1.1 skrll
258 1.1 skrll #define bcm2835_barrier() \
259 1.1 skrll bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
260 1.1 skrll BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
261 1.3 skrll
262 1.1 skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
263 1.1 skrll "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
264 1.1 skrll "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
265 1.2 jakllsch "(unused 8)", "usb", "(unused 10)", "(unused 11)",
266 1.2 jakllsch "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
267 1.4 skrll "dma0", "dma1", "dma2", "dma3",
268 1.4 skrll "dma4", "dma5", "dma6", "dma7",
269 1.4 skrll "dma8", "dma9", "dma10", "dma11",
270 1.4 skrll "dma12", "aux", "(unused 30)", "(unused 31)",
271 1.1 skrll "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
272 1.1 skrll "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
273 1.1 skrll "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
274 1.1 skrll "(unused 44)", "pwa0", "pwa1", "(unused 47)",
275 1.1 skrll "smi", "gpio[0]", "gpio[1]", "gpio[2]",
276 1.1 skrll "gpio[3]", "i2c", "spi", "pcm",
277 1.12 jmcneill "sdhost", "uart", "(unused 58)", "(unused 59)",
278 1.1 skrll "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
279 1.1 skrll "Timer", "Mailbox", "Doorbell0", "Doorbell1",
280 1.1 skrll "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
281 1.1 skrll };
282 1.1 skrll
283 1.8 skrll static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
284 1.5 skrll "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
285 1.5 skrll "mailbox0", "mailbox1", "mailbox2", "mailbox3",
286 1.17 skrll "gpu", "pmu"
287 1.5 skrll };
288 1.5 skrll
289 1.5 skrll #define BCM2836_INTBIT_GPUPENDING __BIT(8)
290 1.5 skrll
291 1.1 skrll #define BCM2835_INTBIT_PENDING1 __BIT(8)
292 1.1 skrll #define BCM2835_INTBIT_PENDING2 __BIT(9)
293 1.1 skrll #define BCM2835_INTBIT_ARM __BITS(0,7)
294 1.1 skrll #define BCM2835_INTBIT_GPU0 __BITS(10,14)
295 1.1 skrll #define BCM2835_INTBIT_GPU1 __BITS(15,20)
296 1.1 skrll
297 1.1 skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
298 1.1 skrll bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
299 1.1 skrll
300 1.35 thorpej static const struct device_compatible_entry compat_data[] = {
301 1.35 thorpej { .compat = "brcm,bcm2708-armctrl-ic", .value = 0 },
302 1.35 thorpej { .compat = "brcm,bcm2709-armctrl-ic", .value = 0 },
303 1.35 thorpej { .compat = "brcm,bcm2835-armctrl-ic", .value = 0 },
304 1.35 thorpej { .compat = "brcm,bcm2836-armctrl-ic", .value = 0 },
305 1.35 thorpej { .compat = "brcm,bcm2836-l1-intc", .value = 1 },
306 1.37 thorpej DEVICE_COMPAT_EOL
307 1.35 thorpej };
308 1.35 thorpej
309 1.1 skrll static int
310 1.1 skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
311 1.1 skrll {
312 1.15 skrll struct fdt_attach_args * const faa = aux;
313 1.1 skrll
314 1.37 thorpej return of_compatible_match(faa->faa_phandle, compat_data);
315 1.1 skrll }
316 1.1 skrll
317 1.1 skrll static void
318 1.1 skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
319 1.1 skrll {
320 1.15 skrll struct bcm2835icu_softc * const sc = device_private(self);
321 1.15 skrll struct fdt_attach_args * const faa = aux;
322 1.15 skrll struct fdtbus_interrupt_controller_func *ifuncs;
323 1.35 thorpej const struct device_compatible_entry *dce;
324 1.15 skrll const int phandle = faa->faa_phandle;
325 1.15 skrll bus_addr_t addr;
326 1.15 skrll bus_size_t size;
327 1.15 skrll bus_space_handle_t ioh;
328 1.15 skrll int error;
329 1.15 skrll
330 1.15 skrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
331 1.15 skrll aprint_error(": couldn't get registers\n");
332 1.15 skrll return;
333 1.15 skrll }
334 1.1 skrll
335 1.1 skrll sc->sc_dev = self;
336 1.15 skrll sc->sc_iot = faa->faa_bst;
337 1.1 skrll
338 1.15 skrll if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
339 1.15 skrll aprint_error(": couldn't map device\n");
340 1.1 skrll return;
341 1.1 skrll }
342 1.1 skrll
343 1.15 skrll sc->sc_ioh = ioh;
344 1.15 skrll sc->sc_phandle = phandle;
345 1.5 skrll
346 1.37 thorpej dce = of_compatible_lookup(faa->faa_phandle, compat_data);
347 1.35 thorpej KASSERT(dce != NULL);
348 1.35 thorpej
349 1.35 thorpej if (dce->value != 0) {
350 1.8 skrll #if defined(MULTIPROCESSOR)
351 1.15 skrll aprint_normal(": Multiprocessor");
352 1.5 skrll #endif
353 1.15 skrll bcml1icu_sc = sc;
354 1.5 skrll
355 1.15 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh,
356 1.15 skrll BCM2836_LOCAL_CONTROL, 0);
357 1.15 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh,
358 1.15 skrll BCM2836_LOCAL_PRESCALER, 0x80000000);
359 1.15 skrll
360 1.15 skrll ifuncs = &bcm2836mpicu_fdt_funcs;
361 1.15 skrll
362 1.15 skrll bcm2836mp_intr_init(self, curcpu());
363 1.15 skrll arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
364 1.15 skrll } else {
365 1.15 skrll if (bcml1icu_sc == NULL)
366 1.15 skrll arm_fdt_irq_set_handler(bcm2835_irq_handler);
367 1.15 skrll bcmicu_sc = sc;
368 1.15 skrll sc->sc_ioh = ioh;
369 1.15 skrll sc->sc_phandle = phandle;
370 1.28 skrll bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
371 1.15 skrll ifuncs = &bcm2835icu_fdt_funcs;
372 1.15 skrll }
373 1.15 skrll
374 1.15 skrll error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
375 1.15 skrll if (error != 0) {
376 1.15 skrll aprint_error(": couldn't register with fdtbus: %d\n", error);
377 1.15 skrll return;
378 1.15 skrll }
379 1.1 skrll aprint_normal("\n");
380 1.1 skrll }
381 1.1 skrll
382 1.15 skrll static void
383 1.1 skrll bcm2835_irq_handler(void *frame)
384 1.1 skrll {
385 1.1 skrll struct cpu_info * const ci = curcpu();
386 1.1 skrll const int oldipl = ci->ci_cpl;
387 1.32 skrll const cpuid_t cpuid = ci->ci_core_id;
388 1.1 skrll const uint32_t oldipl_mask = __BIT(oldipl);
389 1.1 skrll int ipl_mask = 0;
390 1.1 skrll
391 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
392 1.24 skrll
393 1.1 skrll ci->ci_data.cpu_nintr++;
394 1.1 skrll
395 1.1 skrll bcm2835_barrier();
396 1.8 skrll if (cpuid == 0) {
397 1.8 skrll ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
398 1.8 skrll }
399 1.15 skrll #if defined(SOC_BCM2836)
400 1.8 skrll ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
401 1.5 skrll #endif
402 1.1 skrll
403 1.1 skrll /*
404 1.1 skrll * Record the pending_ipls and deliver them if we can.
405 1.1 skrll */
406 1.1 skrll if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
407 1.1 skrll pic_do_pending_ints(I32_bit, oldipl, frame);
408 1.1 skrll }
409 1.1 skrll
410 1.1 skrll static void
411 1.1 skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
412 1.1 skrll uint32_t irq_mask)
413 1.1 skrll {
414 1.1 skrll
415 1.1 skrll write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
416 1.1 skrll bcm2835_barrier();
417 1.1 skrll }
418 1.1 skrll
419 1.1 skrll static void
420 1.1 skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
421 1.1 skrll uint32_t irq_mask)
422 1.1 skrll {
423 1.1 skrll
424 1.1 skrll write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
425 1.1 skrll bcm2835_barrier();
426 1.1 skrll }
427 1.1 skrll
428 1.1 skrll /*
429 1.1 skrll * Called with interrupts disabled
430 1.1 skrll */
431 1.1 skrll static int
432 1.1 skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
433 1.1 skrll {
434 1.1 skrll int ipl = 0;
435 1.1 skrll uint32_t bpending, gpu0irq, gpu1irq, armirq;
436 1.1 skrll
437 1.1 skrll bcm2835_barrier();
438 1.1 skrll bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
439 1.1 skrll if (bpending == 0)
440 1.1 skrll return 0;
441 1.1 skrll
442 1.1 skrll armirq = bpending & BCM2835_INTBIT_ARM;
443 1.1 skrll gpu0irq = bpending & BCM2835_INTBIT_GPU0;
444 1.1 skrll gpu1irq = bpending & BCM2835_INTBIT_GPU1;
445 1.1 skrll
446 1.1 skrll if (armirq) {
447 1.8 skrll ipl |= pic_mark_pending_sources(pic,
448 1.8 skrll BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
449 1.1 skrll }
450 1.1 skrll
451 1.1 skrll if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
452 1.1 skrll uint32_t pending1;
453 1.3 skrll
454 1.1 skrll pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
455 1.8 skrll ipl |= pic_mark_pending_sources(pic,
456 1.8 skrll BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
457 1.1 skrll }
458 1.1 skrll if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
459 1.1 skrll uint32_t pending2;
460 1.3 skrll
461 1.1 skrll pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
462 1.8 skrll ipl |= pic_mark_pending_sources(pic,
463 1.8 skrll BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
464 1.1 skrll }
465 1.3 skrll
466 1.1 skrll return ipl;
467 1.1 skrll }
468 1.1 skrll
469 1.1 skrll static void
470 1.1 skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
471 1.1 skrll {
472 1.1 skrll
473 1.1 skrll /* Nothing really*/
474 1.1 skrll KASSERT(is->is_irq < BCM2835_NIRQ);
475 1.1 skrll KASSERT(is->is_type == IST_LEVEL);
476 1.1 skrll }
477 1.1 skrll
478 1.1 skrll static void
479 1.1 skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
480 1.1 skrll {
481 1.1 skrll
482 1.1 skrll strlcpy(buf, bcm2835_sources[irq], len);
483 1.1 skrll }
484 1.5 skrll
485 1.15 skrll static int
486 1.15 skrll bcm2835_icu_fdt_decode_irq(u_int *specifier)
487 1.15 skrll {
488 1.15 skrll u_int base;
489 1.15 skrll
490 1.15 skrll if (!specifier)
491 1.15 skrll return -1;
492 1.15 skrll
493 1.15 skrll /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
494 1.15 skrll /* 2nd cell is the irq relative to that bank */
495 1.15 skrll
496 1.15 skrll const u_int bank = be32toh(specifier[0]);
497 1.15 skrll switch (bank) {
498 1.15 skrll case 0:
499 1.15 skrll base = BCM2835_INT_BASICBASE;
500 1.15 skrll break;
501 1.15 skrll case 1:
502 1.15 skrll base = BCM2835_INT_GPU0BASE;
503 1.15 skrll break;
504 1.15 skrll case 2:
505 1.15 skrll base = BCM2835_INT_GPU1BASE;
506 1.15 skrll break;
507 1.15 skrll default:
508 1.15 skrll return -1;
509 1.15 skrll }
510 1.15 skrll const u_int off = be32toh(specifier[1]);
511 1.15 skrll
512 1.15 skrll return base + off;
513 1.15 skrll }
514 1.15 skrll
515 1.15 skrll static void *
516 1.15 skrll bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
517 1.34 jmcneill int (*func)(void *), void *arg, const char *xname)
518 1.15 skrll {
519 1.25 thorpej struct bcm2835icu_softc * const sc = device_private(dev);
520 1.25 thorpej struct bcm2835icu_irq *firq;
521 1.25 thorpej struct bcm2835icu_irqhandler *firqh;
522 1.15 skrll int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
523 1.27 thorpej int irq, irqidx;
524 1.15 skrll
525 1.15 skrll irq = bcm2835_icu_fdt_decode_irq(specifier);
526 1.15 skrll if (irq == -1)
527 1.15 skrll return NULL;
528 1.27 thorpej irqidx = irq - BCM2835_INT_BASE;
529 1.5 skrll
530 1.27 thorpej KASSERT(irqidx < BCM2835_NIRQ);
531 1.26 thorpej
532 1.27 thorpej firq = sc->sc_irq[irqidx];
533 1.25 thorpej if (firq == NULL) {
534 1.25 thorpej firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
535 1.25 thorpej firq->intr_sc = sc;
536 1.25 thorpej firq->intr_refcnt = 0;
537 1.25 thorpej firq->intr_arg = arg;
538 1.25 thorpej firq->intr_ipl = ipl;
539 1.25 thorpej firq->intr_mpsafe = iflags;
540 1.25 thorpej firq->intr_irq = irq;
541 1.25 thorpej TAILQ_INIT(&firq->intr_handlers);
542 1.25 thorpej if (arg == NULL) {
543 1.34 jmcneill firq->intr_ih = intr_establish_xname(irq, ipl,
544 1.34 jmcneill IST_LEVEL | iflags, func, NULL, xname);
545 1.25 thorpej } else {
546 1.34 jmcneill firq->intr_ih = intr_establish_xname(irq, ipl,
547 1.34 jmcneill IST_LEVEL | iflags, bcm2835_icu_intr, firq, xname);
548 1.25 thorpej }
549 1.25 thorpej if (firq->intr_ih == NULL) {
550 1.25 thorpej kmem_free(firq, sizeof(*firq));
551 1.25 thorpej return NULL;
552 1.25 thorpej }
553 1.27 thorpej sc->sc_irq[irqidx] = firq;
554 1.25 thorpej } else {
555 1.25 thorpej if (firq->intr_arg == NULL || arg == NULL) {
556 1.25 thorpej device_printf(dev,
557 1.25 thorpej "cannot share irq with NULL-arg handler\n");
558 1.25 thorpej return NULL;
559 1.25 thorpej }
560 1.25 thorpej if (firq->intr_ipl != ipl) {
561 1.25 thorpej device_printf(dev,
562 1.25 thorpej "cannot share irq with different ipl\n");
563 1.25 thorpej return NULL;
564 1.25 thorpej }
565 1.25 thorpej if (firq->intr_mpsafe != iflags) {
566 1.25 thorpej device_printf(dev,
567 1.25 thorpej "cannot share irq between mpsafe/non-mpsafe\n");
568 1.25 thorpej return NULL;
569 1.25 thorpej }
570 1.25 thorpej }
571 1.25 thorpej
572 1.25 thorpej firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
573 1.25 thorpej firqh->ih_irq = firq;
574 1.25 thorpej firqh->ih_fn = func;
575 1.25 thorpej firqh->ih_arg = arg;
576 1.26 thorpej
577 1.26 thorpej firq->intr_refcnt++;
578 1.25 thorpej TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
579 1.25 thorpej
580 1.26 thorpej /*
581 1.26 thorpej * XXX interrupt_distribute(9) assumes that any interrupt
582 1.26 thorpej * handle can be used as an input to the MD interrupt_distribute
583 1.26 thorpej * implementationm, so we are forced to return the handle
584 1.26 thorpej * we got back from intr_establish(). Upshot is that the
585 1.26 thorpej * input to bcm2835_icu_fdt_disestablish() is ambiguous for
586 1.26 thorpej * shared IRQs, rendering them un-disestablishable.
587 1.26 thorpej */
588 1.26 thorpej
589 1.26 thorpej return firq->intr_ih;
590 1.15 skrll }
591 1.15 skrll
592 1.15 skrll static void
593 1.15 skrll bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
594 1.15 skrll {
595 1.25 thorpej struct bcm2835icu_softc * const sc = device_private(dev);
596 1.26 thorpej struct bcm2835icu_irqhandler *firqh;
597 1.26 thorpej struct bcm2835icu_irq *firq;
598 1.26 thorpej u_int n;
599 1.25 thorpej
600 1.26 thorpej for (n = 0; n < BCM2835_NIRQ; n++) {
601 1.26 thorpej firq = sc->sc_irq[n];
602 1.26 thorpej if (firq == NULL || firq->intr_ih != ih)
603 1.26 thorpej continue;
604 1.26 thorpej
605 1.26 thorpej KASSERT(firq->intr_refcnt > 0);
606 1.27 thorpej KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
607 1.26 thorpej
608 1.26 thorpej /* XXX see above */
609 1.26 thorpej if (firq->intr_refcnt > 1)
610 1.26 thorpej panic("%s: cannot disestablish shared irq", __func__);
611 1.25 thorpej
612 1.26 thorpej intr_disestablish(firq->intr_ih);
613 1.25 thorpej
614 1.26 thorpej firqh = TAILQ_FIRST(&firq->intr_handlers);
615 1.26 thorpej TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
616 1.26 thorpej kmem_free(firqh, sizeof(*firqh));
617 1.25 thorpej
618 1.27 thorpej sc->sc_irq[n] = NULL;
619 1.26 thorpej kmem_free(firq, sizeof(*firq));
620 1.26 thorpej
621 1.26 thorpej return;
622 1.26 thorpej }
623 1.25 thorpej
624 1.26 thorpej panic("%s: interrupt not established", __func__);
625 1.25 thorpej }
626 1.25 thorpej
627 1.25 thorpej static int
628 1.25 thorpej bcm2835_icu_intr(void *priv)
629 1.25 thorpej {
630 1.25 thorpej struct bcm2835icu_irq *firq = priv;
631 1.25 thorpej struct bcm2835icu_irqhandler *firqh;
632 1.25 thorpej int handled = 0;
633 1.25 thorpej
634 1.25 thorpej TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
635 1.25 thorpej handled |= firqh->ih_fn(firqh->ih_arg);
636 1.25 thorpej }
637 1.25 thorpej
638 1.25 thorpej return handled;
639 1.15 skrll }
640 1.15 skrll
641 1.15 skrll static bool
642 1.15 skrll bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
643 1.15 skrll {
644 1.15 skrll int irq;
645 1.15 skrll
646 1.15 skrll irq = bcm2835_icu_fdt_decode_irq(specifier);
647 1.15 skrll if (irq == -1)
648 1.15 skrll return false;
649 1.15 skrll
650 1.15 skrll snprintf(buf, buflen, "icu irq %d", irq);
651 1.15 skrll
652 1.15 skrll return true;
653 1.15 skrll }
654 1.5 skrll
655 1.5 skrll #define BCM2836MP_TIMER_IRQS __BITS(3,0)
656 1.19 skrll #define BCM2836MP_MAILBOX_IRQS __BITS(4,7)
657 1.19 skrll #define BCM2836MP_GPU_IRQ __BIT(8)
658 1.19 skrll #define BCM2836MP_PMU_IRQ __BIT(9)
659 1.19 skrll #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
660 1.5 skrll
661 1.5 skrll static void
662 1.5 skrll bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
663 1.5 skrll uint32_t irq_mask)
664 1.5 skrll {
665 1.15 skrll const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
666 1.15 skrll const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
667 1.19 skrll const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
668 1.5 skrll
669 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
670 1.8 skrll KASSERT(irqbase == 0);
671 1.5 skrll
672 1.5 skrll if (irq_mask & BCM2836MP_TIMER_IRQS) {
673 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
674 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
675 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
676 1.5 skrll val |= mask;
677 1.15 skrll bus_space_write_4(iot, ioh,
678 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
679 1.5 skrll val);
680 1.15 skrll bus_space_barrier(iot, ioh,
681 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
682 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
683 1.5 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
684 1.10 skrll }
685 1.10 skrll if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
686 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
687 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
688 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
689 1.5 skrll val |= mask;
690 1.15 skrll bus_space_write_4(iot, ioh,
691 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
692 1.5 skrll val);
693 1.15 skrll bus_space_barrier(iot, ioh,
694 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
695 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
696 1.5 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
697 1.5 skrll }
698 1.19 skrll if (irq_mask & BCM2836MP_PMU_IRQ) {
699 1.19 skrll bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
700 1.19 skrll __BIT(cpuid));
701 1.19 skrll bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
702 1.19 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
703 1.19 skrll }
704 1.5 skrll
705 1.5 skrll return;
706 1.5 skrll }
707 1.5 skrll
708 1.5 skrll static void
709 1.5 skrll bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
710 1.5 skrll uint32_t irq_mask)
711 1.5 skrll {
712 1.15 skrll const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
713 1.15 skrll const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
714 1.19 skrll const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
715 1.8 skrll
716 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
717 1.8 skrll KASSERT(irqbase == 0);
718 1.5 skrll
719 1.5 skrll if (irq_mask & BCM2836MP_TIMER_IRQS) {
720 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
721 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
722 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
723 1.5 skrll val &= ~mask;
724 1.15 skrll bus_space_write_4(iot, ioh,
725 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
726 1.5 skrll val);
727 1.10 skrll }
728 1.10 skrll if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
729 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
730 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
731 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
732 1.5 skrll val &= ~mask;
733 1.15 skrll bus_space_write_4(iot, ioh,
734 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
735 1.5 skrll val);
736 1.5 skrll }
737 1.19 skrll if (irq_mask & BCM2836MP_PMU_IRQ) {
738 1.19 skrll bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
739 1.21 skrll __BIT(cpuid));
740 1.19 skrll }
741 1.5 skrll
742 1.5 skrll bcm2835_barrier();
743 1.5 skrll return;
744 1.5 skrll }
745 1.5 skrll
746 1.5 skrll static int
747 1.5 skrll bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
748 1.5 skrll {
749 1.8 skrll struct cpu_info * const ci = curcpu();
750 1.32 skrll const cpuid_t cpuid = ci->ci_core_id;
751 1.5 skrll uint32_t lpending;
752 1.5 skrll int ipl = 0;
753 1.5 skrll
754 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
755 1.8 skrll KASSERT(pic == &bcm2836mp_pic[cpuid]);
756 1.8 skrll
757 1.5 skrll bcm2835_barrier();
758 1.5 skrll
759 1.15 skrll lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
760 1.5 skrll BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
761 1.5 skrll
762 1.5 skrll lpending &= ~BCM2836_INTBIT_GPUPENDING;
763 1.29 skrll const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
764 1.29 skrll if (allirqs) {
765 1.29 skrll ipl |= pic_mark_pending_sources(pic, 0, allirqs);
766 1.5 skrll }
767 1.5 skrll
768 1.5 skrll return ipl;
769 1.5 skrll }
770 1.5 skrll
771 1.5 skrll static void
772 1.5 skrll bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
773 1.5 skrll {
774 1.5 skrll /* Nothing really*/
775 1.5 skrll KASSERT(is->is_irq >= 0);
776 1.8 skrll KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
777 1.8 skrll }
778 1.8 skrll
779 1.8 skrll static void
780 1.8 skrll bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
781 1.8 skrll {
782 1.8 skrll
783 1.8 skrll irq %= BCM2836_NIRQPERCPU;
784 1.8 skrll strlcpy(buf, bcm2836mp_sources[irq], len);
785 1.8 skrll }
786 1.5 skrll
787 1.5 skrll
788 1.15 skrll #if defined(MULTIPROCESSOR)
789 1.8 skrll static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
790 1.8 skrll {
791 1.32 skrll const cpuid_t cpuid = ci->ci_core_id;
792 1.24 skrll
793 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
794 1.8 skrll
795 1.8 skrll /* Enable IRQ and not FIQ */
796 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
797 1.24 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid), 1);
798 1.5 skrll }
799 1.5 skrll
800 1.5 skrll static void
801 1.8 skrll bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
802 1.8 skrll {
803 1.10 skrll KASSERT(pic != NULL);
804 1.10 skrll KASSERT(pic != &bcm2835_pic);
805 1.10 skrll KASSERT(pic->pic_cpus != NULL);
806 1.10 skrll
807 1.8 skrll const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
808 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
809 1.8 skrll
810 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
811 1.9 jmcneill BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
812 1.8 skrll }
813 1.8 skrll
814 1.8 skrll int
815 1.8 skrll bcm2836mp_ipi_handler(void *priv)
816 1.8 skrll {
817 1.8 skrll const struct cpu_info *ci = curcpu();
818 1.32 skrll const cpuid_t cpuid = ci->ci_core_id;
819 1.9 jmcneill uint32_t ipimask, bit;
820 1.9 jmcneill
821 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
822 1.24 skrll
823 1.15 skrll ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
824 1.8 skrll BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
825 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
826 1.15 skrll BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
827 1.8 skrll
828 1.9 jmcneill while ((bit = ffs(ipimask)) > 0) {
829 1.9 jmcneill const u_int ipi = bit - 1;
830 1.9 jmcneill switch (ipi) {
831 1.9 jmcneill case IPI_AST:
832 1.11 skrll pic_ipi_ast(priv);
833 1.11 skrll break;
834 1.9 jmcneill case IPI_NOP:
835 1.11 skrll pic_ipi_nop(priv);
836 1.11 skrll break;
837 1.9 jmcneill #ifdef __HAVE_PREEMPTION
838 1.9 jmcneill case IPI_KPREEMPT:
839 1.11 skrll pic_ipi_kpreempt(priv);
840 1.11 skrll break;
841 1.9 jmcneill #endif
842 1.9 jmcneill case IPI_XCALL:
843 1.9 jmcneill pic_ipi_xcall(priv);
844 1.9 jmcneill break;
845 1.9 jmcneill case IPI_GENERIC:
846 1.9 jmcneill pic_ipi_generic(priv);
847 1.9 jmcneill break;
848 1.9 jmcneill case IPI_SHOOTDOWN:
849 1.9 jmcneill pic_ipi_shootdown(priv);
850 1.9 jmcneill break;
851 1.8 skrll #ifdef DDB
852 1.9 jmcneill case IPI_DDB:
853 1.9 jmcneill pic_ipi_ddb(priv);
854 1.9 jmcneill break;
855 1.8 skrll #endif
856 1.9 jmcneill }
857 1.9 jmcneill ipimask &= ~__BIT(ipi);
858 1.8 skrll }
859 1.8 skrll
860 1.8 skrll return 1;
861 1.8 skrll }
862 1.15 skrll #endif
863 1.8 skrll
864 1.15 skrll static void
865 1.15 skrll bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
866 1.5 skrll {
867 1.32 skrll const cpuid_t cpuid = ci->ci_core_id;
868 1.8 skrll struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
869 1.8 skrll
870 1.24 skrll KASSERT(cpuid < BCM2836_NCPUS);
871 1.24 skrll
872 1.15 skrll #if defined(MULTIPROCESSOR)
873 1.8 skrll pic->pic_cpus = ci->ci_kcpuset;
874 1.20 ryo
875 1.20 ryo /*
876 1.20 ryo * Append "#n" to avoid duplication of .pic_name[]
877 1.20 ryo * It should be a unique id for intr_get_source()
878 1.20 ryo */
879 1.20 ryo char suffix[sizeof("#00000")];
880 1.20 ryo snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
881 1.20 ryo strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
882 1.15 skrll #endif
883 1.29 skrll bcm2836mp_int_base[cpuid] = pic_add(pic, PIC_IRQBASE_ALLOC);
884 1.8 skrll
885 1.15 skrll #if defined(MULTIPROCESSOR)
886 1.10 skrll intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
887 1.8 skrll IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
888 1.8 skrll
889 1.19 skrll struct bcm2836mp_interrupt *bip;
890 1.19 skrll TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
891 1.19 skrll if (bip->bi_done)
892 1.19 skrll continue;
893 1.19 skrll
894 1.19 skrll const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
895 1.19 skrll void *ih = intr_establish(irq, bip->bi_ipl,
896 1.19 skrll IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
897 1.19 skrll
898 1.19 skrll bip->bi_ihs[cpuid] = ih;
899 1.19 skrll }
900 1.15 skrll #endif
901 1.5 skrll }
902 1.8 skrll
903 1.15 skrll static int
904 1.15 skrll bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
905 1.15 skrll {
906 1.22 skrll
907 1.15 skrll if (!specifier)
908 1.15 skrll return -1;
909 1.19 skrll return be32toh(specifier[0]);
910 1.15 skrll }
911 1.15 skrll
912 1.15 skrll static void *
913 1.15 skrll bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
914 1.34 jmcneill int (*func)(void *), void *arg, const char *xname)
915 1.15 skrll {
916 1.15 skrll int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
917 1.19 skrll struct bcm2836mp_interrupt *bip;
918 1.19 skrll void *ih;
919 1.15 skrll
920 1.19 skrll int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
921 1.15 skrll if (irq == -1)
922 1.15 skrll return NULL;
923 1.15 skrll
924 1.19 skrll TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
925 1.19 skrll if (irq == bip->bi_irq)
926 1.19 skrll return NULL;
927 1.19 skrll }
928 1.19 skrll
929 1.19 skrll bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
930 1.19 skrll if (bip == NULL)
931 1.19 skrll return NULL;
932 1.19 skrll
933 1.19 skrll bip->bi_done = false;
934 1.19 skrll bip->bi_irq = irq;
935 1.19 skrll bip->bi_ipl = ipl;
936 1.19 skrll bip->bi_flags = IST_LEVEL | iflags;
937 1.19 skrll bip->bi_func = func;
938 1.19 skrll bip->bi_arg = arg;
939 1.19 skrll
940 1.19 skrll /*
941 1.33 christos * If we're not cold and the BPs have been started then we can
942 1.33 christos * register the interrupt for all CPUs now, e.g. PMU
943 1.19 skrll */
944 1.19 skrll if (!cold) {
945 1.19 skrll for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
946 1.34 jmcneill ih = intr_establish_xname(
947 1.34 jmcneill BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
948 1.34 jmcneill IST_LEVEL | iflags, func, arg, xname);
949 1.19 skrll if (!ih) {
950 1.19 skrll kmem_free(bip, sizeof(*bip));
951 1.19 skrll return NULL;
952 1.19 skrll }
953 1.19 skrll bip->bi_ihs[cpuid] = ih;
954 1.19 skrll
955 1.19 skrll }
956 1.19 skrll bip->bi_done = true;
957 1.19 skrll ih = bip->bi_ihs[0];
958 1.19 skrll goto done;
959 1.19 skrll }
960 1.19 skrll
961 1.19 skrll /*
962 1.19 skrll * Otherwise we can only establish the interrupt for the BP and
963 1.19 skrll * delay until bcm2836mp_intr_init is called for each AP, e.g.
964 1.19 skrll * gtmr
965 1.19 skrll */
966 1.34 jmcneill ih = intr_establish_xname(BCM2836_INT_BASECPUN(0) + irq, ipl,
967 1.34 jmcneill IST_LEVEL | iflags, func, arg, xname);
968 1.19 skrll if (!ih) {
969 1.19 skrll kmem_free(bip, sizeof(*bip));
970 1.19 skrll return NULL;
971 1.19 skrll }
972 1.19 skrll
973 1.19 skrll bip->bi_ihs[0] = ih;
974 1.19 skrll for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
975 1.19 skrll bip->bi_ihs[cpuid] = NULL;
976 1.19 skrll
977 1.19 skrll done:
978 1.19 skrll TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
979 1.19 skrll
980 1.19 skrll /*
981 1.19 skrll * Return the intr_establish handle for cpu 0 for API compatibility.
982 1.19 skrll * Any cpu would do here as these sources don't support set_affinity
983 1.19 skrll * when the handle is used in interrupt_distribute(9)
984 1.19 skrll */
985 1.19 skrll return ih;
986 1.15 skrll }
987 1.15 skrll
988 1.15 skrll static void
989 1.15 skrll bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
990 1.15 skrll {
991 1.19 skrll struct bcm2836mp_interrupt *bip;
992 1.19 skrll
993 1.19 skrll TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
994 1.19 skrll if (bip->bi_ihs[0] == ih)
995 1.19 skrll break;
996 1.19 skrll }
997 1.19 skrll
998 1.19 skrll if (bip == NULL)
999 1.19 skrll return;
1000 1.19 skrll
1001 1.19 skrll for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
1002 1.19 skrll intr_disestablish(bip->bi_ihs[cpuid]);
1003 1.19 skrll
1004 1.19 skrll TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
1005 1.19 skrll
1006 1.19 skrll kmem_free(bip, sizeof(*bip));
1007 1.15 skrll }
1008 1.15 skrll
1009 1.15 skrll static bool
1010 1.15 skrll bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
1011 1.15 skrll size_t buflen)
1012 1.15 skrll {
1013 1.15 skrll int irq;
1014 1.15 skrll
1015 1.15 skrll irq = bcm2836mp_icu_fdt_decode_irq(specifier);
1016 1.15 skrll if (irq == -1)
1017 1.15 skrll return false;
1018 1.15 skrll
1019 1.15 skrll snprintf(buf, buflen, "local_intc irq %d", irq);
1020 1.15 skrll
1021 1.15 skrll return true;
1022 1.15 skrll }
1023