gic.c revision 276963
1/*- 2 * Copyright (c) 2011 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * Developed by Damjan Marion <damjan.marion@gmail.com> 6 * 7 * Based on OMAP4 GIC 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 * 3. The name of the company nor the name of the author may be used to 18 * endorse or promote products derived from this software without specific 19 * prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/arm/arm/gic.c 276963 2015-01-11 10:26:49Z andrew $"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/bus.h> 40#include <sys/kernel.h> 41#include <sys/ktr.h> 42#include <sys/module.h> 43#include <sys/rman.h> 44#include <sys/pcpu.h> 45#include <sys/proc.h> 46#include <sys/cpuset.h> 47#include <sys/lock.h> 48#include <sys/mutex.h> 49#include <machine/bus.h> 50#include <machine/intr.h> 51#include <machine/smp.h> 52 53#include <dev/fdt/fdt_common.h> 54#include <dev/ofw/openfirm.h> 55#include <dev/ofw/ofw_bus.h> 56#include <dev/ofw/ofw_bus_subr.h> 57 58/* We are using GICv2 register naming */ 59 60/* Distributor Registers */ 61#define GICD_CTLR 0x000 /* v1 ICDDCR */ 62#define GICD_TYPER 0x004 /* v1 ICDICTR */ 63#define GICD_IIDR 0x008 /* v1 ICDIIDR */ 64#define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */ 65#define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */ 66#define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */ 67#define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */ 68#define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */ 69#define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */ 70#define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */ 71#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */ 72#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */ 73#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */ 74 75/* CPU Registers */ 76#define GICC_CTLR 0x0000 /* v1 ICCICR */ 77#define GICC_PMR 0x0004 /* v1 ICCPMR */ 78#define GICC_BPR 0x0008 /* v1 ICCBPR */ 79#define GICC_IAR 0x000C /* v1 ICCIAR */ 80#define GICC_EOIR 0x0010 /* v1 ICCEOIR */ 81#define GICC_RPR 0x0014 /* v1 ICCRPR */ 82#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */ 83#define GICC_ABPR 0x001C /* v1 ICCABPR */ 84#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ 85 86#define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */ 87#define GIC_LAST_IPI 15 88#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */ 89#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */ 90#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */ 91 92/* First bit is a polarity bit (0 - low, 1 - high) */ 93#define GICD_ICFGR_POL_LOW (0 << 0) 94#define GICD_ICFGR_POL_HIGH (1 << 0) 95#define GICD_ICFGR_POL_MASK 0x1 96/* Second bit is a trigger bit (0 - level, 1 - edge) */ 97#define GICD_ICFGR_TRIG_LVL (0 << 1) 98#define GICD_ICFGR_TRIG_EDGE (1 << 1) 99#define GICD_ICFGR_TRIG_MASK 0x2 100 101struct arm_gic_softc { 102 device_t gic_dev; 103 struct resource * gic_res[3]; 104 bus_space_tag_t gic_c_bst; 105 bus_space_tag_t gic_d_bst; 106 bus_space_handle_t gic_c_bsh; 107 bus_space_handle_t gic_d_bsh; 108 uint8_t ver; 109 struct mtx mutex; 110 uint32_t nirqs; 111}; 112 113static struct resource_spec arm_gic_spec[] = { 114 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ 115 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ 116 { -1, 0 } 117}; 118 119static struct arm_gic_softc *arm_gic_sc = NULL; 120 121#define gic_c_read_4(_sc, _reg) \ 122 bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) 123#define gic_c_write_4(_sc, _reg, _val) \ 124 bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) 125#define gic_d_read_4(_sc, _reg) \ 126 bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) 127#define gic_d_write_4(_sc, _reg, _val) \ 128 bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) 129 130static int gic_config_irq(int irq, enum intr_trigger trig, 131 enum intr_polarity pol); 132static void gic_post_filter(void *); 133 134static struct ofw_compat_data compat_data[] = { 135 {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */ 136 {"arm,gic-400", true}, 137 {"arm,cortex-a15-gic", true}, 138 {"arm,cortex-a9-gic", true}, 139 {"arm,cortex-a7-gic", true}, 140 {"arm,arm11mp-gic", true}, 141 {"brcm,brahma-b15-gic", true}, 142 {NULL, false} 143}; 144 145static int 146arm_gic_probe(device_t dev) 147{ 148 149 if (!ofw_bus_status_okay(dev)) 150 return (ENXIO); 151 152 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 153 return (ENXIO); 154 device_set_desc(dev, "ARM Generic Interrupt Controller"); 155 return (BUS_PROBE_DEFAULT); 156} 157 158static void 159arm_gic_init_secondary(device_t dev) 160{ 161 struct arm_gic_softc *sc = device_get_softc(dev); 162 int i; 163 164 for (i = 0; i < sc->nirqs; i += 4) 165 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); 166 167 /* Set all the interrupts to be in Group 0 (secure) */ 168 for (i = 0; i < sc->nirqs; i += 32) { 169 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); 170 } 171 172 /* Enable CPU interface */ 173 gic_c_write_4(sc, GICC_CTLR, 1); 174 175 /* Set priority mask register. */ 176 gic_c_write_4(sc, GICC_PMR, 0xff); 177 178 /* Enable interrupt distribution */ 179 gic_d_write_4(sc, GICD_CTLR, 0x01); 180 181 /* 182 * Activate the timer interrupts: virtual, secure, and non-secure. 183 */ 184 gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F))); 185 gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); 186 gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F))); 187} 188 189int 190gic_decode_fdt(uint32_t iparent, uint32_t *intr, int *interrupt, 191 int *trig, int *pol) 192{ 193 static u_int num_intr_cells; 194 195 if (num_intr_cells == 0) { 196 if (OF_searchencprop(OF_node_from_xref(iparent), 197 "#interrupt-cells", &num_intr_cells, 198 sizeof(num_intr_cells)) == -1) { 199 num_intr_cells = 1; 200 } 201 } 202 203 if (num_intr_cells == 1) { 204 *interrupt = fdt32_to_cpu(intr[0]); 205 *trig = INTR_TRIGGER_CONFORM; 206 *pol = INTR_POLARITY_CONFORM; 207 } else { 208 if (intr[0] == 0) 209 *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI; 210 else 211 *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI; 212 /* 213 * In intr[2], bits[3:0] are trigger type and level flags. 214 * 1 = low-to-high edge triggered 215 * 2 = high-to-low edge triggered 216 * 4 = active high level-sensitive 217 * 8 = active low level-sensitive 218 * The hardware only supports active-high-level or rising-edge. 219 */ 220 if (intr[2] & 0x0a) { 221 printf("unsupported trigger/polarity configuration " 222 "0x%2x\n", intr[2] & 0x0f); 223 return (ENOTSUP); 224 } 225 *pol = INTR_POLARITY_CONFORM; 226 if (intr[2] & 0x01) 227 *trig = INTR_TRIGGER_EDGE; 228 else 229 *trig = INTR_TRIGGER_LEVEL; 230 } 231 return (0); 232} 233 234static int 235arm_gic_attach(device_t dev) 236{ 237 struct arm_gic_softc *sc; 238 int i; 239 uint32_t icciidr; 240 241 if (arm_gic_sc) 242 return (ENXIO); 243 244 sc = device_get_softc(dev); 245 246 if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) { 247 device_printf(dev, "could not allocate resources\n"); 248 return (ENXIO); 249 } 250 251 sc->gic_dev = dev; 252 arm_gic_sc = sc; 253 254 /* Initialize mutex */ 255 mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); 256 257 /* Distributor Interface */ 258 sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); 259 sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]); 260 261 /* CPU Interface */ 262 sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); 263 sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); 264 265 /* Disable interrupt forwarding to the CPU interface */ 266 gic_d_write_4(sc, GICD_CTLR, 0x00); 267 268 /* Get the number of interrupts */ 269 sc->nirqs = gic_d_read_4(sc, GICD_TYPER); 270 sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); 271 272 /* Set up function pointers */ 273 arm_post_filter = gic_post_filter; 274 arm_config_irq = gic_config_irq; 275 276 icciidr = gic_c_read_4(sc, GICC_IIDR); 277 device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n", 278 icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, 279 (icciidr & 0xfff), sc->nirqs); 280 281 /* Set all global interrupts to be level triggered, active low. */ 282 for (i = 32; i < sc->nirqs; i += 16) { 283 gic_d_write_4(sc, GICD_ICFGR(i >> 4), 0x00000000); 284 } 285 286 /* Disable all interrupts. */ 287 for (i = 32; i < sc->nirqs; i += 32) { 288 gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF); 289 } 290 291 for (i = 0; i < sc->nirqs; i += 4) { 292 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); 293 gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), 294 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24); 295 } 296 297 /* Set all the interrupts to be in Group 0 (secure) */ 298 for (i = 0; i < sc->nirqs; i += 32) { 299 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); 300 } 301 302 /* Enable CPU interface */ 303 gic_c_write_4(sc, GICC_CTLR, 1); 304 305 /* Set priority mask register. */ 306 gic_c_write_4(sc, GICC_PMR, 0xff); 307 308 /* Enable interrupt distribution */ 309 gic_d_write_4(sc, GICD_CTLR, 0x01); 310 311 return (0); 312} 313 314static int 315arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) 316{ 317 uint32_t active_irq; 318 319 active_irq = gic_c_read_4(sc, GICC_IAR); 320 321 /* 322 * Immediatly EOIR the SGIs, because doing so requires the other 323 * bits (ie CPU number), not just the IRQ number, and we do not 324 * have this information later. 325 */ 326 if ((active_irq & 0x3ff) <= GIC_LAST_IPI) 327 gic_c_write_4(sc, GICC_EOIR, active_irq); 328 active_irq &= 0x3FF; 329 330 if (active_irq == 0x3FF) { 331 if (last_irq == -1) 332 printf("Spurious interrupt detected\n"); 333 return -1; 334 } 335 336 return active_irq; 337} 338 339static int 340arm_gic_config(device_t dev, int irq, enum intr_trigger trig, 341 enum intr_polarity pol) 342{ 343 struct arm_gic_softc *sc = device_get_softc(dev); 344 uint32_t reg; 345 uint32_t mask; 346 347 /* Function is public-accessible, so validate input arguments */ 348 if ((irq < 0) || (irq >= sc->nirqs)) 349 goto invalid_args; 350 if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) && 351 (trig != INTR_TRIGGER_CONFORM)) 352 goto invalid_args; 353 if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) && 354 (pol != INTR_POLARITY_CONFORM)) 355 goto invalid_args; 356 357 mtx_lock_spin(&sc->mutex); 358 359 reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); 360 mask = (reg >> 2*(irq % 16)) & 0x3; 361 362 if (pol == INTR_POLARITY_LOW) { 363 mask &= ~GICD_ICFGR_POL_MASK; 364 mask |= GICD_ICFGR_POL_LOW; 365 } else if (pol == INTR_POLARITY_HIGH) { 366 mask &= ~GICD_ICFGR_POL_MASK; 367 mask |= GICD_ICFGR_POL_HIGH; 368 } 369 370 if (trig == INTR_TRIGGER_LEVEL) { 371 mask &= ~GICD_ICFGR_TRIG_MASK; 372 mask |= GICD_ICFGR_TRIG_LVL; 373 } else if (trig == INTR_TRIGGER_EDGE) { 374 mask &= ~GICD_ICFGR_TRIG_MASK; 375 mask |= GICD_ICFGR_TRIG_EDGE; 376 } 377 378 /* Set mask */ 379 reg = reg & ~(0x3 << 2*(irq % 16)); 380 reg = reg | (mask << 2*(irq % 16)); 381 gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); 382 383 mtx_unlock_spin(&sc->mutex); 384 385 return (0); 386 387invalid_args: 388 device_printf(dev, "gic_config_irg, invalid parameters\n"); 389 return (EINVAL); 390} 391 392 393static void 394arm_gic_mask(device_t dev, int irq) 395{ 396 struct arm_gic_softc *sc = device_get_softc(dev); 397 398 gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); 399 gic_c_write_4(sc, GICC_EOIR, irq); 400} 401 402static void 403arm_gic_unmask(device_t dev, int irq) 404{ 405 struct arm_gic_softc *sc = device_get_softc(dev); 406 407 if (irq > GIC_LAST_IPI) 408 arm_irq_memory_barrier(irq); 409 410 gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); 411} 412 413#ifdef SMP 414static void 415arm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi) 416{ 417 struct arm_gic_softc *sc = device_get_softc(dev); 418 uint32_t val = 0, i; 419 420 for (i = 0; i < MAXCPU; i++) 421 if (CPU_ISSET(i, &cpus)) 422 val |= 1 << (16 + i); 423 424 gic_d_write_4(sc, GICD_SGIR(0), val | ipi); 425} 426 427static int 428arm_gic_ipi_read(device_t dev, int i) 429{ 430 431 if (i != -1) { 432 /* 433 * The intr code will automagically give the frame pointer 434 * if the interrupt argument is 0. 435 */ 436 if ((unsigned int)i > 16) 437 return (0); 438 return (i); 439 } 440 441 return (0x3ff); 442} 443 444static void 445arm_gic_ipi_clear(device_t dev, int ipi) 446{ 447 /* no-op */ 448} 449#endif 450 451static void 452gic_post_filter(void *arg) 453{ 454 struct arm_gic_softc *sc = arm_gic_sc; 455 uintptr_t irq = (uintptr_t) arg; 456 457 if (irq > GIC_LAST_IPI) 458 arm_irq_memory_barrier(irq); 459 gic_c_write_4(sc, GICC_EOIR, irq); 460} 461 462static int 463gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol) 464{ 465 466 return (arm_gic_config(arm_gic_sc->gic_dev, irq, trig, pol)); 467} 468 469void 470arm_mask_irq(uintptr_t nb) 471{ 472 473 arm_gic_mask(arm_gic_sc->gic_dev, nb); 474} 475 476void 477arm_unmask_irq(uintptr_t nb) 478{ 479 480 arm_gic_unmask(arm_gic_sc->gic_dev, nb); 481} 482 483int 484arm_get_next_irq(int last_irq) 485{ 486 487 return (arm_gic_next_irq(arm_gic_sc, last_irq)); 488} 489 490void 491gic_init_secondary(void) 492{ 493 494 arm_gic_init_secondary(arm_gic_sc->gic_dev); 495} 496 497#ifdef SMP 498void 499pic_ipi_send(cpuset_t cpus, u_int ipi) 500{ 501 502 arm_gic_ipi_send(arm_gic_sc->gic_dev, cpus, ipi); 503} 504 505int 506pic_ipi_read(int i) 507{ 508 509 return (arm_gic_ipi_read(arm_gic_sc->gic_dev, i)); 510} 511 512void 513pic_ipi_clear(int ipi) 514{ 515 516 arm_gic_ipi_clear(arm_gic_sc->gic_dev, ipi); 517} 518#endif 519 520static device_method_t arm_gic_methods[] = { 521 /* Device interface */ 522 DEVMETHOD(device_probe, arm_gic_probe), 523 DEVMETHOD(device_attach, arm_gic_attach), 524 { 0, 0 } 525}; 526 527static driver_t arm_gic_driver = { 528 "gic", 529 arm_gic_methods, 530 sizeof(struct arm_gic_softc), 531}; 532 533static devclass_t arm_gic_devclass; 534 535EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0, 536 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 537EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0, 538 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 539