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#include "qapi/error.h"
  26
  27/* Interrupt Handlers */
  28struct 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
  42struct 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
  64static 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
  92static 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
 111static 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 */
 138static 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
 157static 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
 235static 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
 328static 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
 338static 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
 367static 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
 382static 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
 391static 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
 397static 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->user_creatable = false;
 405    dc->realize = omap_intc_realize;
 406}
 407
 408static 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
 415static 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
 496static 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                            __func__);
 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
 604static 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
 614static 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
 630static 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
 644static 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
 652static 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->user_creatable = false;
 660    dc->realize = omap2_intc_realize;
 661}
 662
 663static 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
 670static 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
 677static 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
 684type_init(omap_intc_register_types)
 685