1 /* 2 * TI OMAP interrupt controller emulation. 3 * 4 * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org> 5 * Copyright (C) 2007-2008 Nokia Corporation 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 or 10 * (at your option) version 3 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 #include "qemu/osdep.h" 21 #include "hw/hw.h" 22 #include "hw/arm/omap.h" 23 #include "hw/sysbus.h" 24 #include "qemu/error-report.h" 25 #include "qapi/error.h" 26 27 /* Interrupt Handlers */ 28 struct omap_intr_handler_bank_s { 29 uint32_t irqs; 30 uint32_t inputs; 31 uint32_t mask; 32 uint32_t fiq; 33 uint32_t sens_edge; 34 uint32_t swi; 35 unsigned char priority[32]; 36 }; 37 38 #define TYPE_OMAP_INTC "common-omap-intc" 39 #define OMAP_INTC(obj) \ 40 OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC) 41 42 struct omap_intr_handler_s { 43 SysBusDevice parent_obj; 44 45 qemu_irq *pins; 46 qemu_irq parent_intr[2]; 47 MemoryRegion mmio; 48 void *iclk; 49 void *fclk; 50 unsigned char nbanks; 51 int level_only; 52 uint32_t size; 53 54 uint8_t revision; 55 56 /* state */ 57 uint32_t new_agr[2]; 58 int sir_intr[2]; 59 int autoidle; 60 uint32_t mask; 61 struct omap_intr_handler_bank_s bank[3]; 62 }; 63 64 static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) 65 { 66 int i, j, sir_intr, p_intr, p; 67 uint32_t level; 68 sir_intr = 0; 69 p_intr = 255; 70 71 /* Find the interrupt line with the highest dynamic priority. 72 * Note: 0 denotes the hightest priority. 73 * If all interrupts have the same priority, the default order is IRQ_N, 74 * IRQ_N-1,...,IRQ_0. */ 75 for (j = 0; j < s->nbanks; ++j) { 76 level = s->bank[j].irqs & ~s->bank[j].mask & 77 (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq); 78 79 while (level != 0) { 80 i = ctz32(level); 81 p = s->bank[j].priority[i]; 82 if (p <= p_intr) { 83 p_intr = p; 84 sir_intr = 32 * j + i; 85 } 86 level &= level - 1; 87 } 88 } 89 s->sir_intr[is_fiq] = sir_intr; 90 } 91 92 static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) 93 { 94 int i; 95 uint32_t has_intr = 0; 96 97 for (i = 0; i < s->nbanks; ++i) 98 has_intr |= s->bank[i].irqs & ~s->bank[i].mask & 99 (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq); 100 101 if (s->new_agr[is_fiq] & has_intr & s->mask) { 102 s->new_agr[is_fiq] = 0; 103 omap_inth_sir_update(s, is_fiq); 104 qemu_set_irq(s->parent_intr[is_fiq], 1); 105 } 106 } 107 108 #define INT_FALLING_EDGE 0 109 #define INT_LOW_LEVEL 1 110 111 static void omap_set_intr(void *opaque, int irq, int req) 112 { 113 struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; 114 uint32_t rise; 115 116 struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; 117 int n = irq & 31; 118 119 if (req) { 120 rise = ~bank->irqs & (1 << n); 121 if (~bank->sens_edge & (1 << n)) 122 rise &= ~bank->inputs; 123 124 bank->inputs |= (1 << n); 125 if (rise) { 126 bank->irqs |= rise; 127 omap_inth_update(ih, 0); 128 omap_inth_update(ih, 1); 129 } 130 } else { 131 rise = bank->sens_edge & bank->irqs & (1 << n); 132 bank->irqs &= ~rise; 133 bank->inputs &= ~(1 << n); 134 } 135 } 136 137 /* Simplified version with no edge detection */ 138 static void omap_set_intr_noedge(void *opaque, int irq, int req) 139 { 140 struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; 141 uint32_t rise; 142 143 struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; 144 int n = irq & 31; 145 146 if (req) { 147 rise = ~bank->inputs & (1 << n); 148 if (rise) { 149 bank->irqs |= bank->inputs |= rise; 150 omap_inth_update(ih, 0); 151 omap_inth_update(ih, 1); 152 } 153 } else 154 bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi; 155 } 156 157 static uint64_t omap_inth_read(void *opaque, hwaddr addr, 158 unsigned size) 159 { 160 struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; 161 int i, offset = addr; 162 int bank_no = offset >> 8; 163 int line_no; 164 struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; 165 offset &= 0xff; 166 167 switch (offset) { 168 case 0x00: /* ITR */ 169 return bank->irqs; 170 171 case 0x04: /* MIR */ 172 return bank->mask; 173 174 case 0x10: /* SIR_IRQ_CODE */ 175 case 0x14: /* SIR_FIQ_CODE */ 176 if (bank_no != 0) 177 break; 178 line_no = s->sir_intr[(offset - 0x10) >> 2]; 179 bank = &s->bank[line_no >> 5]; 180 i = line_no & 31; 181 if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) 182 bank->irqs &= ~(1 << i); 183 return line_no; 184 185 case 0x18: /* CONTROL_REG */ 186 if (bank_no != 0) 187 break; 188 return 0; 189 190 case 0x1c: /* ILR0 */ 191 case 0x20: /* ILR1 */ 192 case 0x24: /* ILR2 */ 193 case 0x28: /* ILR3 */ 194 case 0x2c: /* ILR4 */ 195 case 0x30: /* ILR5 */ 196 case 0x34: /* ILR6 */ 197 case 0x38: /* ILR7 */ 198 case 0x3c: /* ILR8 */ 199 case 0x40: /* ILR9 */ 200 case 0x44: /* ILR10 */ 201 case 0x48: /* ILR11 */ 202 case 0x4c: /* ILR12 */ 203 case 0x50: /* ILR13 */ 204 case 0x54: /* ILR14 */ 205 case 0x58: /* ILR15 */ 206 case 0x5c: /* ILR16 */ 207 case 0x60: /* ILR17 */ 208 case 0x64: /* ILR18 */ 209 case 0x68: /* ILR19 */ 210 case 0x6c: /* ILR20 */ 211 case 0x70: /* ILR21 */ 212 case 0x74: /* ILR22 */ 213 case 0x78: /* ILR23 */ 214 case 0x7c: /* ILR24 */ 215 case 0x80: /* ILR25 */ 216 case 0x84: /* ILR26 */ 217 case 0x88: /* ILR27 */ 218 case 0x8c: /* ILR28 */ 219 case 0x90: /* ILR29 */ 220 case 0x94: /* ILR30 */ 221 case 0x98: /* ILR31 */ 222 i = (offset - 0x1c) >> 2; 223 return (bank->priority[i] << 2) | 224 (((bank->sens_edge >> i) & 1) << 1) | 225 ((bank->fiq >> i) & 1); 226 227 case 0x9c: /* ISR */ 228 return 0x00000000; 229 230 } 231 OMAP_BAD_REG(addr); 232 return 0; 233 } 234 235 static void omap_inth_write(void *opaque, hwaddr addr, 236 uint64_t value, unsigned size) 237 { 238 struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; 239 int i, offset = addr; 240 int bank_no = offset >> 8; 241 struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; 242 offset &= 0xff; 243 244 switch (offset) { 245 case 0x00: /* ITR */ 246 /* Important: ignore the clearing if the IRQ is level-triggered and 247 the input bit is 1 */ 248 bank->irqs &= value | (bank->inputs & bank->sens_edge); 249 return; 250 251 case 0x04: /* MIR */ 252 bank->mask = value; 253 omap_inth_update(s, 0); 254 omap_inth_update(s, 1); 255 return; 256 257 case 0x10: /* SIR_IRQ_CODE */ 258 case 0x14: /* SIR_FIQ_CODE */ 259 OMAP_RO_REG(addr); 260 break; 261 262 case 0x18: /* CONTROL_REG */ 263 if (bank_no != 0) 264 break; 265 if (value & 2) { 266 qemu_set_irq(s->parent_intr[1], 0); 267 s->new_agr[1] = ~0; 268 omap_inth_update(s, 1); 269 } 270 if (value & 1) { 271 qemu_set_irq(s->parent_intr[0], 0); 272 s->new_agr[0] = ~0; 273 omap_inth_update(s, 0); 274 } 275 return; 276 277 case 0x1c: /* ILR0 */ 278 case 0x20: /* ILR1 */ 279 case 0x24: /* ILR2 */ 280 case 0x28: /* ILR3 */ 281 case 0x2c: /* ILR4 */ 282 case 0x30: /* ILR5 */ 283 case 0x34: /* ILR6 */ 284 case 0x38: /* ILR7 */ 285 case 0x3c: /* ILR8 */ 286 case 0x40: /* ILR9 */ 287 case 0x44: /* ILR10 */ 288 case 0x48: /* ILR11 */ 289 case 0x4c: /* ILR12 */ 290 case 0x50: /* ILR13 */ 291 case 0x54: /* ILR14 */ 292 case 0x58: /* ILR15 */ 293 case 0x5c: /* ILR16 */ 294 case 0x60: /* ILR17 */ 295 case 0x64: /* ILR18 */ 296 case 0x68: /* ILR19 */ 297 case 0x6c: /* ILR20 */ 298 case 0x70: /* ILR21 */ 299 case 0x74: /* ILR22 */ 300 case 0x78: /* ILR23 */ 301 case 0x7c: /* ILR24 */ 302 case 0x80: /* ILR25 */ 303 case 0x84: /* ILR26 */ 304 case 0x88: /* ILR27 */ 305 case 0x8c: /* ILR28 */ 306 case 0x90: /* ILR29 */ 307 case 0x94: /* ILR30 */ 308 case 0x98: /* ILR31 */ 309 i = (offset - 0x1c) >> 2; 310 bank->priority[i] = (value >> 2) & 0x1f; 311 bank->sens_edge &= ~(1 << i); 312 bank->sens_edge |= ((value >> 1) & 1) << i; 313 bank->fiq &= ~(1 << i); 314 bank->fiq |= (value & 1) << i; 315 return; 316 317 case 0x9c: /* ISR */ 318 for (i = 0; i < 32; i ++) 319 if (value & (1 << i)) { 320 omap_set_intr(s, 32 * bank_no + i, 1); 321 return; 322 } 323 return; 324 } 325 OMAP_BAD_REG(addr); 326 } 327 328 static const MemoryRegionOps omap_inth_mem_ops = { 329 .read = omap_inth_read, 330 .write = omap_inth_write, 331 .endianness = DEVICE_NATIVE_ENDIAN, 332 .valid = { 333 .min_access_size = 4, 334 .max_access_size = 4, 335 }, 336 }; 337 338 static void omap_inth_reset(DeviceState *dev) 339 { 340 struct omap_intr_handler_s *s = OMAP_INTC(dev); 341 int i; 342 343 for (i = 0; i < s->nbanks; ++i){ 344 s->bank[i].irqs = 0x00000000; 345 s->bank[i].mask = 0xffffffff; 346 s->bank[i].sens_edge = 0x00000000; 347 s->bank[i].fiq = 0x00000000; 348 s->bank[i].inputs = 0x00000000; 349 s->bank[i].swi = 0x00000000; 350 memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority)); 351 352 if (s->level_only) 353 s->bank[i].sens_edge = 0xffffffff; 354 } 355 356 s->new_agr[0] = ~0; 357 s->new_agr[1] = ~0; 358 s->sir_intr[0] = 0; 359 s->sir_intr[1] = 0; 360 s->autoidle = 0; 361 s->mask = ~0; 362 363 qemu_set_irq(s->parent_intr[0], 0); 364 qemu_set_irq(s->parent_intr[1], 0); 365 } 366 367 static void omap_intc_init(Object *obj) 368 { 369 DeviceState *dev = DEVICE(obj); 370 struct omap_intr_handler_s *s = OMAP_INTC(obj); 371 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 372 373 s->nbanks = 1; 374 sysbus_init_irq(sbd, &s->parent_intr[0]); 375 sysbus_init_irq(sbd, &s->parent_intr[1]); 376 qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32); 377 memory_region_init_io(&s->mmio, obj, &omap_inth_mem_ops, s, 378 "omap-intc", s->size); 379 sysbus_init_mmio(sbd, &s->mmio); 380 } 381 382 static void omap_intc_realize(DeviceState *dev, Error **errp) 383 { 384 struct omap_intr_handler_s *s = OMAP_INTC(dev); 385 386 if (!s->iclk) { 387 error_setg(errp, "omap-intc: clk not connected"); 388 } 389 } 390 391 static Property omap_intc_properties[] = { 392 DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100), 393 DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk), 394 DEFINE_PROP_END_OF_LIST(), 395 }; 396 397 static void omap_intc_class_init(ObjectClass *klass, void *data) 398 { 399 DeviceClass *dc = DEVICE_CLASS(klass); 400 401 dc->reset = omap_inth_reset; 402 dc->props = omap_intc_properties; 403 /* Reason: pointer property "clk" */ 404 dc->cannot_instantiate_with_device_add_yet = true; 405 dc->realize = omap_intc_realize; 406 } 407 408 static const TypeInfo omap_intc_info = { 409 .name = "omap-intc", 410 .parent = TYPE_OMAP_INTC, 411 .instance_init = omap_intc_init, 412 .class_init = omap_intc_class_init, 413 }; 414 415 static uint64_t omap2_inth_read(void *opaque, hwaddr addr, 416 unsigned size) 417 { 418 struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; 419 int offset = addr; 420 int bank_no, line_no; 421 struct omap_intr_handler_bank_s *bank = NULL; 422 423 if ((offset & 0xf80) == 0x80) { 424 bank_no = (offset & 0x60) >> 5; 425 if (bank_no < s->nbanks) { 426 offset &= ~0x60; 427 bank = &s->bank[bank_no]; 428 } else { 429 OMAP_BAD_REG(addr); 430 return 0; 431 } 432 } 433 434 switch (offset) { 435 case 0x00: /* INTC_REVISION */ 436 return s->revision; 437 438 case 0x10: /* INTC_SYSCONFIG */ 439 return (s->autoidle >> 2) & 1; 440 441 case 0x14: /* INTC_SYSSTATUS */ 442 return 1; /* RESETDONE */ 443 444 case 0x40: /* INTC_SIR_IRQ */ 445 return s->sir_intr[0]; 446 447 case 0x44: /* INTC_SIR_FIQ */ 448 return s->sir_intr[1]; 449 450 case 0x48: /* INTC_CONTROL */ 451 return (!s->mask) << 2; /* GLOBALMASK */ 452 453 case 0x4c: /* INTC_PROTECTION */ 454 return 0; 455 456 case 0x50: /* INTC_IDLE */ 457 return s->autoidle & 3; 458 459 /* Per-bank registers */ 460 case 0x80: /* INTC_ITR */ 461 return bank->inputs; 462 463 case 0x84: /* INTC_MIR */ 464 return bank->mask; 465 466 case 0x88: /* INTC_MIR_CLEAR */ 467 case 0x8c: /* INTC_MIR_SET */ 468 return 0; 469 470 case 0x90: /* INTC_ISR_SET */ 471 return bank->swi; 472 473 case 0x94: /* INTC_ISR_CLEAR */ 474 return 0; 475 476 case 0x98: /* INTC_PENDING_IRQ */ 477 return bank->irqs & ~bank->mask & ~bank->fiq; 478 479 case 0x9c: /* INTC_PENDING_FIQ */ 480 return bank->irqs & ~bank->mask & bank->fiq; 481 482 /* Per-line registers */ 483 case 0x100 ... 0x300: /* INTC_ILR */ 484 bank_no = (offset - 0x100) >> 7; 485 if (bank_no > s->nbanks) 486 break; 487 bank = &s->bank[bank_no]; 488 line_no = (offset & 0x7f) >> 2; 489 return (bank->priority[line_no] << 2) | 490 ((bank->fiq >> line_no) & 1); 491 } 492 OMAP_BAD_REG(addr); 493 return 0; 494 } 495 496 static void omap2_inth_write(void *opaque, hwaddr addr, 497 uint64_t value, unsigned size) 498 { 499 struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; 500 int offset = addr; 501 int bank_no, line_no; 502 struct omap_intr_handler_bank_s *bank = NULL; 503 504 if ((offset & 0xf80) == 0x80) { 505 bank_no = (offset & 0x60) >> 5; 506 if (bank_no < s->nbanks) { 507 offset &= ~0x60; 508 bank = &s->bank[bank_no]; 509 } else { 510 OMAP_BAD_REG(addr); 511 return; 512 } 513 } 514 515 switch (offset) { 516 case 0x10: /* INTC_SYSCONFIG */ 517 s->autoidle &= 4; 518 s->autoidle |= (value & 1) << 2; 519 if (value & 2) { /* SOFTRESET */ 520 omap_inth_reset(DEVICE(s)); 521 } 522 return; 523 524 case 0x48: /* INTC_CONTROL */ 525 s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */ 526 if (value & 2) { /* NEWFIQAGR */ 527 qemu_set_irq(s->parent_intr[1], 0); 528 s->new_agr[1] = ~0; 529 omap_inth_update(s, 1); 530 } 531 if (value & 1) { /* NEWIRQAGR */ 532 qemu_set_irq(s->parent_intr[0], 0); 533 s->new_agr[0] = ~0; 534 omap_inth_update(s, 0); 535 } 536 return; 537 538 case 0x4c: /* INTC_PROTECTION */ 539 /* TODO: Make a bitmap (or sizeof(char)map) of access privileges 540 * for every register, see Chapter 3 and 4 for privileged mode. */ 541 if (value & 1) 542 fprintf(stderr, "%s: protection mode enable attempt\n", 543 __FUNCTION__); 544 return; 545 546 case 0x50: /* INTC_IDLE */ 547 s->autoidle &= ~3; 548 s->autoidle |= value & 3; 549 return; 550 551 /* Per-bank registers */ 552 case 0x84: /* INTC_MIR */ 553 bank->mask = value; 554 omap_inth_update(s, 0); 555 omap_inth_update(s, 1); 556 return; 557 558 case 0x88: /* INTC_MIR_CLEAR */ 559 bank->mask &= ~value; 560 omap_inth_update(s, 0); 561 omap_inth_update(s, 1); 562 return; 563 564 case 0x8c: /* INTC_MIR_SET */ 565 bank->mask |= value; 566 return; 567 568 case 0x90: /* INTC_ISR_SET */ 569 bank->irqs |= bank->swi |= value; 570 omap_inth_update(s, 0); 571 omap_inth_update(s, 1); 572 return; 573 574 case 0x94: /* INTC_ISR_CLEAR */ 575 bank->swi &= ~value; 576 bank->irqs = bank->swi & bank->inputs; 577 return; 578 579 /* Per-line registers */ 580 case 0x100 ... 0x300: /* INTC_ILR */ 581 bank_no = (offset - 0x100) >> 7; 582 if (bank_no > s->nbanks) 583 break; 584 bank = &s->bank[bank_no]; 585 line_no = (offset & 0x7f) >> 2; 586 bank->priority[line_no] = (value >> 2) & 0x3f; 587 bank->fiq &= ~(1 << line_no); 588 bank->fiq |= (value & 1) << line_no; 589 return; 590 591 case 0x00: /* INTC_REVISION */ 592 case 0x14: /* INTC_SYSSTATUS */ 593 case 0x40: /* INTC_SIR_IRQ */ 594 case 0x44: /* INTC_SIR_FIQ */ 595 case 0x80: /* INTC_ITR */ 596 case 0x98: /* INTC_PENDING_IRQ */ 597 case 0x9c: /* INTC_PENDING_FIQ */ 598 OMAP_RO_REG(addr); 599 return; 600 } 601 OMAP_BAD_REG(addr); 602 } 603 604 static const MemoryRegionOps omap2_inth_mem_ops = { 605 .read = omap2_inth_read, 606 .write = omap2_inth_write, 607 .endianness = DEVICE_NATIVE_ENDIAN, 608 .valid = { 609 .min_access_size = 4, 610 .max_access_size = 4, 611 }, 612 }; 613 614 static void omap2_intc_init(Object *obj) 615 { 616 DeviceState *dev = DEVICE(obj); 617 struct omap_intr_handler_s *s = OMAP_INTC(obj); 618 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 619 620 s->level_only = 1; 621 s->nbanks = 3; 622 sysbus_init_irq(sbd, &s->parent_intr[0]); 623 sysbus_init_irq(sbd, &s->parent_intr[1]); 624 qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32); 625 memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s, 626 "omap2-intc", 0x1000); 627 sysbus_init_mmio(sbd, &s->mmio); 628 } 629 630 static void omap2_intc_realize(DeviceState *dev, Error **errp) 631 { 632 struct omap_intr_handler_s *s = OMAP_INTC(dev); 633 634 if (!s->iclk) { 635 error_setg(errp, "omap2-intc: iclk not connected"); 636 return; 637 } 638 if (!s->fclk) { 639 error_setg(errp, "omap2-intc: fclk not connected"); 640 return; 641 } 642 } 643 644 static Property omap2_intc_properties[] = { 645 DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s, 646 revision, 0x21), 647 DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk), 648 DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk), 649 DEFINE_PROP_END_OF_LIST(), 650 }; 651 652 static void omap2_intc_class_init(ObjectClass *klass, void *data) 653 { 654 DeviceClass *dc = DEVICE_CLASS(klass); 655 656 dc->reset = omap_inth_reset; 657 dc->props = omap2_intc_properties; 658 /* Reason: pointer property "iclk", "fclk" */ 659 dc->cannot_instantiate_with_device_add_yet = true; 660 dc->realize = omap2_intc_realize; 661 } 662 663 static const TypeInfo omap2_intc_info = { 664 .name = "omap2-intc", 665 .parent = TYPE_OMAP_INTC, 666 .instance_init = omap2_intc_init, 667 .class_init = omap2_intc_class_init, 668 }; 669 670 static const TypeInfo omap_intc_type_info = { 671 .name = TYPE_OMAP_INTC, 672 .parent = TYPE_SYS_BUS_DEVICE, 673 .instance_size = sizeof(struct omap_intr_handler_s), 674 .abstract = true, 675 }; 676 677 static void omap_intc_register_types(void) 678 { 679 type_register_static(&omap_intc_type_info); 680 type_register_static(&omap_intc_info); 681 type_register_static(&omap2_intc_info); 682 } 683 684 type_init(omap_intc_register_types) 685