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