1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> 5 * All rights reserved. 6 * 7 * Based on OMAP3 INTC code by Ben Gray 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "opt_platform.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/ktr.h> 41 #include <sys/module.h> 42 #include <sys/proc.h> 43 #include <sys/rman.h> 44 #include <machine/bus.h> 45 #include <machine/intr.h> 46 47 #include <dev/ofw/openfirm.h> 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 51 #include "pic_if.h" 52 53 #define INTC_PENDING_BASIC 0x00 54 #define INTC_PENDING_BANK1 0x04 55 #define INTC_PENDING_BANK2 0x08 56 #define INTC_FIQ_CONTROL 0x0C 57 #define INTC_ENABLE_BANK1 0x10 58 #define INTC_ENABLE_BANK2 0x14 59 #define INTC_ENABLE_BASIC 0x18 60 #define INTC_DISABLE_BANK1 0x1C 61 #define INTC_DISABLE_BANK2 0x20 62 #define INTC_DISABLE_BASIC 0x24 63 64 #define INTC_PENDING_BASIC_ARM 0x0000FF 65 #define INTC_PENDING_BASIC_GPU1_PEND 0x000100 66 #define INTC_PENDING_BASIC_GPU2_PEND 0x000200 67 #define INTC_PENDING_BASIC_GPU1_7 0x000400 68 #define INTC_PENDING_BASIC_GPU1_9 0x000800 69 #define INTC_PENDING_BASIC_GPU1_10 0x001000 70 #define INTC_PENDING_BASIC_GPU1_18 0x002000 71 #define INTC_PENDING_BASIC_GPU1_19 0x004000 72 #define INTC_PENDING_BASIC_GPU2_21 0x008000 73 #define INTC_PENDING_BASIC_GPU2_22 0x010000 74 #define INTC_PENDING_BASIC_GPU2_23 0x020000 75 #define INTC_PENDING_BASIC_GPU2_24 0x040000 76 #define INTC_PENDING_BASIC_GPU2_25 0x080000 77 #define INTC_PENDING_BASIC_GPU2_30 0x100000 78 #define INTC_PENDING_BASIC_MASK 0x1FFFFF 79 80 #define INTC_PENDING_BASIC_GPU1_MASK (INTC_PENDING_BASIC_GPU1_7 | \ 81 INTC_PENDING_BASIC_GPU1_9 | \ 82 INTC_PENDING_BASIC_GPU1_10 | \ 83 INTC_PENDING_BASIC_GPU1_18 | \ 84 INTC_PENDING_BASIC_GPU1_19) 85 86 #define INTC_PENDING_BASIC_GPU2_MASK (INTC_PENDING_BASIC_GPU2_21 | \ 87 INTC_PENDING_BASIC_GPU2_22 | \ 88 INTC_PENDING_BASIC_GPU2_23 | \ 89 INTC_PENDING_BASIC_GPU2_24 | \ 90 INTC_PENDING_BASIC_GPU2_25 | \ 91 INTC_PENDING_BASIC_GPU2_30) 92 93 #define INTC_PENDING_BANK1_MASK (~((1 << 7) | (1 << 9) | (1 << 10) | \ 94 (1 << 18) | (1 << 19))) 95 #define INTC_PENDING_BANK2_MASK (~((1 << 21) | (1 << 22) | (1 << 23) | \ 96 (1 << 24) | (1 << 25) | (1 << 30))) 97 98 #define BANK1_START 8 99 #define BANK1_END (BANK1_START + 32 - 1) 100 #define BANK2_START (BANK1_START + 32) 101 #define BANK2_END (BANK2_START + 32 - 1) 102 103 #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) 104 #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) 105 #define IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END)) 106 #define IRQ_BANK1(n) ((n) - BANK1_START) 107 #define IRQ_BANK2(n) ((n) - BANK2_START) 108 109 #ifdef DEBUG 110 #define dprintf(fmt, args...) printf(fmt, ##args) 111 #else 112 #define dprintf(fmt, args...) 113 #endif 114 115 #define BCM_INTC_NIRQS 72 /* 8 + 32 + 32 */ 116 117 struct bcm_intc_irqsrc { 118 struct intr_irqsrc bii_isrc; 119 u_int bii_irq; 120 uint16_t bii_disable_reg; 121 uint16_t bii_enable_reg; 122 uint32_t bii_mask; 123 }; 124 125 struct bcm_intc_softc { 126 device_t sc_dev; 127 struct resource * intc_res; 128 bus_space_tag_t intc_bst; 129 bus_space_handle_t intc_bsh; 130 struct resource * intc_irq_res; 131 void * intc_irq_hdl; 132 struct bcm_intc_irqsrc intc_isrcs[BCM_INTC_NIRQS]; 133 }; 134 135 static struct ofw_compat_data compat_data[] = { 136 {"broadcom,bcm2835-armctrl-ic", 1}, 137 {"brcm,bcm2835-armctrl-ic", 1}, 138 {"brcm,bcm2836-armctrl-ic", 1}, 139 {NULL, 0} 140 }; 141 142 static struct bcm_intc_softc *bcm_intc_sc = NULL; 143 144 #define intc_read_4(_sc, reg) \ 145 bus_space_read_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg)) 146 #define intc_write_4(_sc, reg, val) \ 147 bus_space_write_4((_sc)->intc_bst, (_sc)->intc_bsh, (reg), (val)) 148 149 static inline void 150 bcm_intc_isrc_mask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) 151 { 152 153 intc_write_4(sc, bii->bii_disable_reg, bii->bii_mask); 154 } 155 156 static inline void 157 bcm_intc_isrc_unmask(struct bcm_intc_softc *sc, struct bcm_intc_irqsrc *bii) 158 { 159 160 intc_write_4(sc, bii->bii_enable_reg, bii->bii_mask); 161 } 162 163 static inline int 164 bcm2835_intc_active_intr(struct bcm_intc_softc *sc) 165 { 166 uint32_t pending, pending_gpu; 167 168 pending = intc_read_4(sc, INTC_PENDING_BASIC) & INTC_PENDING_BASIC_MASK; 169 if (pending == 0) 170 return (-1); 171 if (pending & INTC_PENDING_BASIC_ARM) 172 return (ffs(pending) - 1); 173 if (pending & INTC_PENDING_BASIC_GPU1_MASK) { 174 if (pending & INTC_PENDING_BASIC_GPU1_7) 175 return (BANK1_START + 7); 176 if (pending & INTC_PENDING_BASIC_GPU1_9) 177 return (BANK1_START + 9); 178 if (pending & INTC_PENDING_BASIC_GPU1_10) 179 return (BANK1_START + 10); 180 if (pending & INTC_PENDING_BASIC_GPU1_18) 181 return (BANK1_START + 18); 182 if (pending & INTC_PENDING_BASIC_GPU1_19) 183 return (BANK1_START + 19); 184 } 185 if (pending & INTC_PENDING_BASIC_GPU2_MASK) { 186 if (pending & INTC_PENDING_BASIC_GPU2_21) 187 return (BANK2_START + 21); 188 if (pending & INTC_PENDING_BASIC_GPU2_22) 189 return (BANK2_START + 22); 190 if (pending & INTC_PENDING_BASIC_GPU2_23) 191 return (BANK2_START + 23); 192 if (pending & INTC_PENDING_BASIC_GPU2_24) 193 return (BANK2_START + 24); 194 if (pending & INTC_PENDING_BASIC_GPU2_25) 195 return (BANK2_START + 25); 196 if (pending & INTC_PENDING_BASIC_GPU2_30) 197 return (BANK2_START + 30); 198 } 199 if (pending & INTC_PENDING_BASIC_GPU1_PEND) { 200 pending_gpu = intc_read_4(sc, INTC_PENDING_BANK1); 201 pending_gpu &= INTC_PENDING_BANK1_MASK; 202 if (pending_gpu != 0) 203 return (BANK1_START + ffs(pending_gpu) - 1); 204 } 205 if (pending & INTC_PENDING_BASIC_GPU2_PEND) { 206 pending_gpu = intc_read_4(sc, INTC_PENDING_BANK2); 207 pending_gpu &= INTC_PENDING_BANK2_MASK; 208 if (pending_gpu != 0) 209 return (BANK2_START + ffs(pending_gpu) - 1); 210 } 211 return (-1); /* It shouldn't end here, but it's hardware. */ 212 } 213 214 static int 215 bcm2835_intc_intr(void *arg) 216 { 217 int irq, num; 218 struct bcm_intc_softc *sc = arg; 219 220 for (num = 0; ; num++) { 221 irq = bcm2835_intc_active_intr(sc); 222 if (irq == -1) 223 break; 224 if (intr_isrc_dispatch(&sc->intc_isrcs[irq].bii_isrc, 225 curthread->td_intr_frame) != 0) { 226 bcm_intc_isrc_mask(sc, &sc->intc_isrcs[irq]); 227 device_printf(sc->sc_dev, "Stray irq %u disabled\n", 228 irq); 229 } 230 arm_irq_memory_barrier(0); /* XXX */ 231 } 232 if (num == 0 && bootverbose) 233 device_printf(sc->sc_dev, "Spurious interrupt detected\n"); 234 235 return (FILTER_HANDLED); 236 } 237 238 static void 239 bcm_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc) 240 { 241 struct bcm_intc_irqsrc *bii = (struct bcm_intc_irqsrc *)isrc; 242 243 arm_irq_memory_barrier(bii->bii_irq); 244 bcm_intc_isrc_unmask(device_get_softc(dev), bii); 245 } 246 247 static void 248 bcm_intc_disable_intr(device_t dev, struct intr_irqsrc *isrc) 249 { 250 251 bcm_intc_isrc_mask(device_get_softc(dev), 252 (struct bcm_intc_irqsrc *)isrc); 253 } 254 255 static int 256 bcm_intc_map_intr(device_t dev, struct intr_map_data *data, 257 struct intr_irqsrc **isrcp) 258 { 259 u_int irq; 260 struct intr_map_data_fdt *daf; 261 struct bcm_intc_softc *sc; 262 bool valid; 263 264 if (data->type != INTR_MAP_DATA_FDT) 265 return (ENOTSUP); 266 267 daf = (struct intr_map_data_fdt *)data; 268 if (daf->ncells == 1) 269 irq = daf->cells[0]; 270 else if (daf->ncells == 2) { 271 valid = true; 272 switch (daf->cells[0]) { 273 case 0: 274 irq = daf->cells[1]; 275 if (irq >= BANK1_START) 276 valid = false; 277 break; 278 case 1: 279 irq = daf->cells[1] + BANK1_START; 280 if (irq > BANK1_END) 281 valid = false; 282 break; 283 case 2: 284 irq = daf->cells[1] + BANK2_START; 285 if (irq > BANK2_END) 286 valid = false; 287 break; 288 default: 289 valid = false; 290 break; 291 } 292 293 if (!valid) { 294 device_printf(dev, 295 "invalid IRQ config: bank=%d, irq=%d\n", 296 daf->cells[0], daf->cells[1]); 297 return (EINVAL); 298 } 299 } 300 else 301 return (EINVAL); 302 303 if (irq >= BCM_INTC_NIRQS) 304 return (EINVAL); 305 306 sc = device_get_softc(dev); 307 *isrcp = &sc->intc_isrcs[irq].bii_isrc; 308 return (0); 309 } 310 311 static void 312 bcm_intc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 313 { 314 315 bcm_intc_disable_intr(dev, isrc); 316 } 317 318 static void 319 bcm_intc_post_ithread(device_t dev, struct intr_irqsrc *isrc) 320 { 321 322 bcm_intc_enable_intr(dev, isrc); 323 } 324 325 static void 326 bcm_intc_post_filter(device_t dev, struct intr_irqsrc *isrc) 327 { 328 } 329 330 static int 331 bcm_intc_pic_register(struct bcm_intc_softc *sc, intptr_t xref) 332 { 333 struct bcm_intc_irqsrc *bii; 334 int error; 335 uint32_t irq; 336 const char *name; 337 338 name = device_get_nameunit(sc->sc_dev); 339 for (irq = 0; irq < BCM_INTC_NIRQS; irq++) { 340 bii = &sc->intc_isrcs[irq]; 341 bii->bii_irq = irq; 342 if (IS_IRQ_BASIC(irq)) { 343 bii->bii_disable_reg = INTC_DISABLE_BASIC; 344 bii->bii_enable_reg = INTC_ENABLE_BASIC; 345 bii->bii_mask = 1 << irq; 346 } else if (IS_IRQ_BANK1(irq)) { 347 bii->bii_disable_reg = INTC_DISABLE_BANK1; 348 bii->bii_enable_reg = INTC_ENABLE_BANK1; 349 bii->bii_mask = 1 << IRQ_BANK1(irq); 350 } else if (IS_IRQ_BANK2(irq)) { 351 bii->bii_disable_reg = INTC_DISABLE_BANK2; 352 bii->bii_enable_reg = INTC_ENABLE_BANK2; 353 bii->bii_mask = 1 << IRQ_BANK2(irq); 354 } else 355 return (ENXIO); 356 357 error = intr_isrc_register(&bii->bii_isrc, sc->sc_dev, 0, 358 "%s,%u", name, irq); 359 if (error != 0) 360 return (error); 361 } 362 if (intr_pic_register(sc->sc_dev, xref) == NULL) 363 return (ENXIO); 364 365 return (0); 366 } 367 368 static int 369 bcm_intc_probe(device_t dev) 370 { 371 372 if (!ofw_bus_status_okay(dev)) 373 return (ENXIO); 374 375 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 376 return (ENXIO); 377 378 device_set_desc(dev, "BCM2835 Interrupt Controller"); 379 return (BUS_PROBE_DEFAULT); 380 } 381 382 static int 383 bcm_intc_attach(device_t dev) 384 { 385 struct bcm_intc_softc *sc = device_get_softc(dev); 386 int rid = 0; 387 intptr_t xref; 388 sc->sc_dev = dev; 389 390 if (bcm_intc_sc) 391 return (ENXIO); 392 393 sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 394 if (sc->intc_res == NULL) { 395 device_printf(dev, "could not allocate memory resource\n"); 396 return (ENXIO); 397 } 398 399 xref = OF_xref_from_node(ofw_bus_get_node(dev)); 400 if (bcm_intc_pic_register(sc, xref) != 0) { 401 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_res); 402 device_printf(dev, "could not register PIC\n"); 403 return (ENXIO); 404 } 405 406 rid = 0; 407 sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 408 RF_ACTIVE); 409 if (sc->intc_irq_res == NULL) { 410 if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc, 0) != 0) { 411 /* XXX clean up */ 412 device_printf(dev, "could not set PIC as a root\n"); 413 return (ENXIO); 414 } 415 } else { 416 if (bus_setup_intr(dev, sc->intc_irq_res, INTR_TYPE_CLK, 417 bcm2835_intc_intr, NULL, sc, &sc->intc_irq_hdl)) { 418 /* XXX clean up */ 419 device_printf(dev, "could not setup irq handler\n"); 420 return (ENXIO); 421 } 422 } 423 sc->intc_bst = rman_get_bustag(sc->intc_res); 424 sc->intc_bsh = rman_get_bushandle(sc->intc_res); 425 426 bcm_intc_sc = sc; 427 428 return (0); 429 } 430 431 static device_method_t bcm_intc_methods[] = { 432 DEVMETHOD(device_probe, bcm_intc_probe), 433 DEVMETHOD(device_attach, bcm_intc_attach), 434 435 DEVMETHOD(pic_disable_intr, bcm_intc_disable_intr), 436 DEVMETHOD(pic_enable_intr, bcm_intc_enable_intr), 437 DEVMETHOD(pic_map_intr, bcm_intc_map_intr), 438 DEVMETHOD(pic_post_filter, bcm_intc_post_filter), 439 DEVMETHOD(pic_post_ithread, bcm_intc_post_ithread), 440 DEVMETHOD(pic_pre_ithread, bcm_intc_pre_ithread), 441 { 0, 0 } 442 }; 443 444 static driver_t bcm_intc_driver = { 445 "intc", 446 bcm_intc_methods, 447 sizeof(struct bcm_intc_softc), 448 }; 449 450 EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, 0, 0, 451 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 452