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