1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 Benno Rice. 5 * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD. 6 * Copyright (c) 2012 Semihalf. 7 * All rights reserved. 8 * 9 * Developed by Semihalf. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1 32 * from: FreeBSD: src/sys/arm/mv/ic.c,v 1.5 2011/02/08 01:49:30 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include "opt_platform.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/bus.h> 43 #include <sys/kernel.h> 44 #include <sys/cpuset.h> 45 #include <sys/ktr.h> 46 #include <sys/kdb.h> 47 #include <sys/module.h> 48 #include <sys/lock.h> 49 #include <sys/mutex.h> 50 #include <sys/rman.h> 51 #include <sys/proc.h> 52 #include <sys/smp.h> 53 54 #include <machine/bus.h> 55 #include <machine/intr.h> 56 #include <machine/smp.h> 57 58 #include <arm/mv/mvvar.h> 59 #include <arm/mv/mvreg.h> 60 61 #include <dev/ofw/ofw_bus.h> 62 #include <dev/ofw/ofw_bus_subr.h> 63 #include <dev/fdt/fdt_common.h> 64 65 #ifdef INTRNG 66 #include "pic_if.h" 67 #endif 68 69 #ifdef DEBUG 70 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 71 printf(fmt,##args); } while (0) 72 #else 73 #define debugf(fmt, args...) 74 #endif 75 76 #define MPIC_INT_LOCAL 3 77 #define MPIC_INT_ERR 4 78 #define MPIC_INT_MSI 96 79 80 #define MPIC_IRQ_MASK 0x3ff 81 82 #define MPIC_CTRL 0x0 83 #define MPIC_SOFT_INT 0x4 84 #define MPIC_SOFT_INT_DRBL1 (1 << 5) 85 #define MPIC_ERR_CAUSE 0x20 86 #define MPIC_ISE 0x30 87 #define MPIC_ICE 0x34 88 #define MPIC_INT_CTL(irq) (0x100 + (irq)*4) 89 90 #define MPIC_INT_IRQ_FIQ_MASK(cpuid) (0x101 << (cpuid)) 91 #define MPIC_CTRL_NIRQS(ctrl) (((ctrl) >> 2) & 0x3ff) 92 93 #define MPIC_IN_DRBL 0x08 94 #define MPIC_IN_DRBL_MASK 0x0c 95 #define MPIC_PPI_CAUSE 0x10 96 #define MPIC_CTP 0x40 97 #define MPIC_IIACK 0x44 98 #define MPIC_ISM 0x48 99 #define MPIC_ICM 0x4c 100 #define MPIC_ERR_MASK 0x50 101 #define MPIC_LOCAL_MASK 0x54 102 #define MPIC_CPU(n) (n) * 0x100 103 104 #define MPIC_PPI 32 105 106 #ifdef INTRNG 107 struct mv_mpic_irqsrc { 108 struct intr_irqsrc mmi_isrc; 109 u_int mmi_irq; 110 }; 111 #endif 112 113 struct mv_mpic_softc { 114 device_t sc_dev; 115 struct resource * mpic_res[4]; 116 bus_space_tag_t mpic_bst; 117 bus_space_handle_t mpic_bsh; 118 bus_space_tag_t cpu_bst; 119 bus_space_handle_t cpu_bsh; 120 bus_space_tag_t drbl_bst; 121 bus_space_handle_t drbl_bsh; 122 struct mtx mtx; 123 #ifdef INTRNG 124 struct mv_mpic_irqsrc * mpic_isrcs; 125 #endif 126 int nirqs; 127 void * intr_hand; 128 }; 129 130 static struct resource_spec mv_mpic_spec[] = { 131 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 132 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 133 { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL }, 134 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, 135 { -1, 0 } 136 }; 137 138 static struct ofw_compat_data compat_data[] = { 139 {"mrvl,mpic", true}, 140 {"marvell,mpic", true}, 141 {NULL, false} 142 }; 143 144 static struct mv_mpic_softc *mv_mpic_sc = NULL; 145 146 void mpic_send_ipi(int cpus, u_int ipi); 147 148 static int mv_mpic_probe(device_t); 149 static int mv_mpic_attach(device_t); 150 uint32_t mv_mpic_get_cause(void); 151 uint32_t mv_mpic_get_cause_err(void); 152 uint32_t mv_mpic_get_msi(void); 153 static void mpic_unmask_irq(uintptr_t nb); 154 static void mpic_mask_irq(uintptr_t nb); 155 static void mpic_mask_irq_err(uintptr_t nb); 156 static void mpic_unmask_irq_err(uintptr_t nb); 157 static boolean_t mpic_irq_is_percpu(uintptr_t); 158 #ifdef INTRNG 159 static int mpic_intr(void *arg); 160 #endif 161 static void mpic_unmask_msi(void); 162 163 #define MPIC_WRITE(softc, reg, val) \ 164 bus_space_write_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg), (val)) 165 #define MPIC_READ(softc, reg) \ 166 bus_space_read_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg)) 167 168 #define MPIC_CPU_WRITE(softc, reg, val) \ 169 bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val)) 170 #define MPIC_CPU_READ(softc, reg) \ 171 bus_space_read_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg)) 172 173 #define MPIC_DRBL_WRITE(softc, reg, val) \ 174 bus_space_write_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg), (val)) 175 #define MPIC_DRBL_READ(softc, reg) \ 176 bus_space_read_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg)) 177 178 static int 179 mv_mpic_probe(device_t dev) 180 { 181 182 if (!ofw_bus_status_okay(dev)) 183 return (ENXIO); 184 185 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 186 return (ENXIO); 187 188 device_set_desc(dev, "Marvell Integrated Interrupt Controller"); 189 return (0); 190 } 191 192 #ifdef INTRNG 193 static int 194 mv_mpic_register_isrcs(struct mv_mpic_softc *sc) 195 { 196 int error; 197 uint32_t irq; 198 struct intr_irqsrc *isrc; 199 const char *name; 200 201 sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF, 202 M_WAITOK | M_ZERO); 203 204 name = device_get_nameunit(sc->sc_dev); 205 for (irq = 0; irq < sc->nirqs; irq++) { 206 sc->mpic_isrcs[irq].mmi_irq = irq; 207 208 isrc = &sc->mpic_isrcs[irq].mmi_isrc; 209 if (irq < MPIC_PPI) { 210 error = intr_isrc_register(isrc, sc->sc_dev, 211 INTR_ISRCF_PPI, "%s", name); 212 } else { 213 error = intr_isrc_register(isrc, sc->sc_dev, 0, "%s", 214 name); 215 } 216 if (error != 0) { 217 /* XXX call intr_isrc_deregister() */ 218 device_printf(sc->sc_dev, "%s failed", __func__); 219 return (error); 220 } 221 } 222 return (0); 223 } 224 #endif 225 226 static int 227 mv_mpic_attach(device_t dev) 228 { 229 struct mv_mpic_softc *sc; 230 int error; 231 uint32_t val; 232 int cpu; 233 234 sc = (struct mv_mpic_softc *)device_get_softc(dev); 235 236 if (mv_mpic_sc != NULL) 237 return (ENXIO); 238 mv_mpic_sc = sc; 239 240 sc->sc_dev = dev; 241 242 mtx_init(&sc->mtx, "MPIC lock", NULL, MTX_SPIN); 243 244 error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res); 245 if (error) { 246 device_printf(dev, "could not allocate resources\n"); 247 return (ENXIO); 248 } 249 #ifdef INTRNG 250 if (sc->mpic_res[3] == NULL) 251 device_printf(dev, "No interrupt to use.\n"); 252 else 253 bus_setup_intr(dev, sc->mpic_res[3], INTR_TYPE_CLK, 254 mpic_intr, NULL, sc, &sc->intr_hand); 255 #endif 256 257 sc->mpic_bst = rman_get_bustag(sc->mpic_res[0]); 258 sc->mpic_bsh = rman_get_bushandle(sc->mpic_res[0]); 259 260 sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]); 261 sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]); 262 263 if (sc->mpic_res[2] != NULL) { 264 /* This is required only if MSIs are used. */ 265 sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]); 266 sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]); 267 } 268 269 MPIC_WRITE(mv_mpic_sc, MPIC_CTRL, 1); 270 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0); 271 272 val = MPIC_READ(mv_mpic_sc, MPIC_CTRL); 273 sc->nirqs = MPIC_CTRL_NIRQS(val); 274 275 #ifdef INTRNG 276 if (mv_mpic_register_isrcs(sc) != 0) { 277 device_printf(dev, "could not register PIC ISRCs\n"); 278 bus_release_resources(dev, mv_mpic_spec, sc->mpic_res); 279 return (ENXIO); 280 } 281 282 OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); 283 284 if (intr_pic_register(dev, OF_xref_from_device(dev)) == NULL) { 285 device_printf(dev, "could not register PIC\n"); 286 bus_release_resources(dev, mv_mpic_spec, sc->mpic_res); 287 return (ENXIO); 288 } 289 #endif 290 291 mpic_unmask_msi(); 292 293 /* Unmask CPU performance counters overflow irq */ 294 for (cpu = 0; cpu < mp_ncpus; cpu++) 295 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CPU(cpu) + MPIC_LOCAL_MASK, 296 (1 << cpu) | MPIC_CPU_READ(mv_mpic_sc, 297 MPIC_CPU(cpu) + MPIC_LOCAL_MASK)); 298 299 return (0); 300 } 301 302 #ifdef INTRNG 303 static int 304 mpic_intr(void *arg) 305 { 306 struct mv_mpic_softc *sc; 307 uint32_t cause, irqsrc; 308 unsigned int irq; 309 u_int cpuid; 310 311 sc = arg; 312 cpuid = PCPU_GET(cpuid); 313 irq = 0; 314 315 for (cause = MPIC_CPU_READ(sc, MPIC_PPI_CAUSE); cause > 0; 316 cause >>= 1, irq++) { 317 if (cause & 1) { 318 irqsrc = MPIC_READ(sc, MPIC_INT_CTL(irq)); 319 if ((irqsrc & MPIC_INT_IRQ_FIQ_MASK(cpuid)) == 0) 320 continue; 321 if (intr_isrc_dispatch(&sc->mpic_isrcs[irq].mmi_isrc, 322 curthread->td_intr_frame) != 0) { 323 mpic_mask_irq(irq); 324 device_printf(sc->sc_dev, "Stray irq %u " 325 "disabled\n", irq); 326 } 327 } 328 } 329 330 return (FILTER_HANDLED); 331 } 332 333 static void 334 mpic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 335 { 336 u_int irq; 337 338 irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq; 339 mpic_mask_irq(irq); 340 } 341 342 static void 343 mpic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 344 { 345 u_int irq; 346 347 irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq; 348 mpic_unmask_irq(irq); 349 } 350 351 static int 352 mpic_map_intr(device_t dev, struct intr_map_data *data, 353 struct intr_irqsrc **isrcp) 354 { 355 struct intr_map_data_fdt *daf; 356 struct mv_mpic_softc *sc; 357 358 if (data->type != INTR_MAP_DATA_FDT) 359 return (ENOTSUP); 360 361 sc = device_get_softc(dev); 362 daf = (struct intr_map_data_fdt *)data; 363 364 if (daf->ncells !=1 || daf->cells[0] >= sc->nirqs) 365 return (EINVAL); 366 367 *isrcp = &sc->mpic_isrcs[daf->cells[0]].mmi_isrc; 368 return (0); 369 } 370 371 static void 372 mpic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 373 { 374 375 mpic_disable_intr(dev, isrc); 376 } 377 378 static void 379 mpic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 380 { 381 382 mpic_enable_intr(dev, isrc); 383 } 384 385 static void 386 mpic_post_filter(device_t dev, struct intr_irqsrc *isrc) 387 { 388 } 389 #endif 390 391 static device_method_t mv_mpic_methods[] = { 392 DEVMETHOD(device_probe, mv_mpic_probe), 393 DEVMETHOD(device_attach, mv_mpic_attach), 394 395 #ifdef INTRNG 396 DEVMETHOD(pic_disable_intr, mpic_disable_intr), 397 DEVMETHOD(pic_enable_intr, mpic_enable_intr), 398 DEVMETHOD(pic_map_intr, mpic_map_intr), 399 DEVMETHOD(pic_post_filter, mpic_post_filter), 400 DEVMETHOD(pic_post_ithread, mpic_post_ithread), 401 DEVMETHOD(pic_pre_ithread, mpic_pre_ithread), 402 #endif 403 { 0, 0 } 404 }; 405 406 static driver_t mv_mpic_driver = { 407 "mpic", 408 mv_mpic_methods, 409 sizeof(struct mv_mpic_softc), 410 }; 411 412 static devclass_t mv_mpic_devclass; 413 414 EARLY_DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0, 415 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 416 417 #ifndef INTRNG 418 int 419 arm_get_next_irq(int last) 420 { 421 u_int irq, next = -1; 422 423 irq = mv_mpic_get_cause() & MPIC_IRQ_MASK; 424 CTR2(KTR_INTR, "%s: irq:%#x", __func__, irq); 425 426 if (irq != MPIC_IRQ_MASK) { 427 if (irq == MPIC_INT_ERR) 428 irq = mv_mpic_get_cause_err(); 429 if (irq == MPIC_INT_MSI) 430 irq = mv_mpic_get_msi(); 431 next = irq; 432 } 433 434 CTR3(KTR_INTR, "%s: last=%d, next=%d", __func__, last, next); 435 return (next); 436 } 437 438 /* 439 * XXX We can make arm_enable_irq to operate on ICE and then mask/unmask only 440 * by ISM/ICM and remove access to ICE in masking operation 441 */ 442 void 443 arm_mask_irq(uintptr_t nb) 444 { 445 446 mpic_mask_irq(nb); 447 } 448 449 void 450 arm_unmask_irq(uintptr_t nb) 451 { 452 453 mpic_unmask_irq(nb); 454 } 455 #endif 456 457 static void 458 mpic_unmask_msi(void) 459 { 460 461 mpic_unmask_irq(MPIC_INT_MSI); 462 } 463 464 static void 465 mpic_unmask_irq_err(uintptr_t nb) 466 { 467 uint32_t mask; 468 uint8_t bit_off; 469 470 MPIC_WRITE(mv_mpic_sc, MPIC_ISE, MPIC_INT_ERR); 471 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, MPIC_INT_ERR); 472 473 bit_off = nb - ERR_IRQ; 474 mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK); 475 mask |= (1 << bit_off); 476 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask); 477 } 478 479 static void 480 mpic_mask_irq_err(uintptr_t nb) 481 { 482 uint32_t mask; 483 uint8_t bit_off; 484 485 bit_off = nb - ERR_IRQ; 486 mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK); 487 mask &= ~(1 << bit_off); 488 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask); 489 } 490 491 static boolean_t 492 mpic_irq_is_percpu(uintptr_t nb) 493 { 494 if (nb < MPIC_PPI) 495 return TRUE; 496 497 return FALSE; 498 } 499 500 static void 501 mpic_unmask_irq(uintptr_t nb) 502 { 503 504 #ifdef SMP 505 int cpu; 506 507 if (nb == MPIC_INT_LOCAL) { 508 for (cpu = 0; cpu < mp_ncpus; cpu++) 509 MPIC_CPU_WRITE(mv_mpic_sc, 510 MPIC_CPU(cpu) + MPIC_ICM, nb); 511 return; 512 } 513 #endif 514 if (mpic_irq_is_percpu(nb)) 515 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb); 516 else if (nb < ERR_IRQ) 517 MPIC_WRITE(mv_mpic_sc, MPIC_ISE, nb); 518 else if (nb < MSI_IRQ) 519 mpic_unmask_irq_err(nb); 520 521 if (nb == 0) 522 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff); 523 } 524 525 static void 526 mpic_mask_irq(uintptr_t nb) 527 { 528 529 #ifdef SMP 530 int cpu; 531 532 if (nb == MPIC_INT_LOCAL) { 533 for (cpu = 0; cpu < mp_ncpus; cpu++) 534 MPIC_CPU_WRITE(mv_mpic_sc, 535 MPIC_CPU(cpu) + MPIC_ISM, nb); 536 return; 537 } 538 #endif 539 if (mpic_irq_is_percpu(nb)) 540 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb); 541 else if (nb < ERR_IRQ) 542 MPIC_WRITE(mv_mpic_sc, MPIC_ICE, nb); 543 else if (nb < MSI_IRQ) 544 mpic_mask_irq_err(nb); 545 } 546 547 uint32_t 548 mv_mpic_get_cause(void) 549 { 550 551 return (MPIC_CPU_READ(mv_mpic_sc, MPIC_IIACK)); 552 } 553 554 uint32_t 555 mv_mpic_get_cause_err(void) 556 { 557 uint32_t err_cause; 558 uint8_t bit_off; 559 560 err_cause = MPIC_READ(mv_mpic_sc, MPIC_ERR_CAUSE); 561 562 if (err_cause) 563 bit_off = ffs(err_cause) - 1; 564 else 565 return (-1); 566 567 debugf("%s: irq:%x cause:%x\n", __func__, bit_off, err_cause); 568 return (ERR_IRQ + bit_off); 569 } 570 571 uint32_t 572 mv_mpic_get_msi(void) 573 { 574 uint32_t cause; 575 uint8_t bit_off; 576 577 KASSERT(mv_mpic_sc->drbl_bst != NULL, ("No doorbell in mv_mpic_get_msi")); 578 cause = MPIC_DRBL_READ(mv_mpic_sc, 0); 579 580 if (cause) 581 bit_off = ffs(cause) - 1; 582 else 583 return (-1); 584 585 debugf("%s: irq:%x cause:%x\n", __func__, bit_off, cause); 586 587 cause &= ~(1 << bit_off); 588 MPIC_DRBL_WRITE(mv_mpic_sc, 0, cause); 589 590 return (MSI_IRQ + bit_off); 591 } 592 593 int 594 mv_msi_data(int irq, uint64_t *addr, uint32_t *data) 595 { 596 u_long phys, base, size; 597 phandle_t node; 598 int error; 599 600 node = ofw_bus_get_node(mv_mpic_sc->sc_dev); 601 602 /* Get physical address of register space */ 603 error = fdt_get_range(OF_parent(node), 0, &phys, &size); 604 if (error) { 605 printf("%s: Cannot get register physical address, err:%d", 606 __func__, error); 607 return (error); 608 } 609 610 /* Get offset of MPIC register space */ 611 error = fdt_regsize(node, &base, &size); 612 if (error) { 613 printf("%s: Cannot get MPIC register offset, err:%d", 614 __func__, error); 615 return (error); 616 } 617 618 *addr = phys + base + MPIC_SOFT_INT; 619 *data = MPIC_SOFT_INT_DRBL1 | irq; 620 621 return (0); 622 } 623 624 625 #if defined(SMP) && defined(SOC_MV_ARMADAXP) 626 void 627 intr_pic_init_secondary(void) 628 { 629 } 630 631 void 632 pic_ipi_send(cpuset_t cpus, u_int ipi) 633 { 634 uint32_t val, i; 635 636 val = 0x00000000; 637 for (i = 0; i < MAXCPU; i++) 638 if (CPU_ISSET(i, &cpus)) 639 val |= (1 << (8 + i)); 640 val |= ipi; 641 MPIC_WRITE(mv_mpic_sc, MPIC_SOFT_INT, val); 642 } 643 644 int 645 pic_ipi_read(int i __unused) 646 { 647 uint32_t val; 648 int ipi; 649 650 val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DRBL); 651 if (val) { 652 ipi = ffs(val) - 1; 653 MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL, ~(1 << ipi)); 654 return (ipi); 655 } 656 657 return (0x3ff); 658 } 659 660 void 661 pic_ipi_clear(int ipi) 662 { 663 } 664 665 #endif 666