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
  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 void omap_intc_init(Object *obj)
 367{
 368    DeviceState *dev = DEVICE(obj);
 369    struct omap_intr_handler_s *s = OMAP_INTC(obj);
 370    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 371
 372    s->nbanks = 1;
 373    sysbus_init_irq(sbd, &s->parent_intr[0]);
 374    sysbus_init_irq(sbd, &s->parent_intr[1]);
 375    qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32);
 376    memory_region_init_io(&s->mmio, obj, &omap_inth_mem_ops, s,
 377                          "omap-intc", s->size);
 378    sysbus_init_mmio(sbd, &s->mmio);
 379}
 380
 381static void omap_intc_realize(DeviceState *dev, Error **errp)
 382{
 383    struct omap_intr_handler_s *s = OMAP_INTC(dev);
 384
 385    if (!s->iclk) {
 386        error_setg(errp, "omap-intc: clk not connected");
 387    }
 388}
 389
 390void omap_intc_set_iclk(omap_intr_handler *intc, omap_clk clk)
 391{
 392    intc->iclk = clk;
 393}
 394
 395void omap_intc_set_fclk(omap_intr_handler *intc, omap_clk clk)
 396{
 397    intc->fclk = clk;
 398}
 399
 400static Property omap_intc_properties[] = {
 401    DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
 402    DEFINE_PROP_END_OF_LIST(),
 403};
 404
 405static void omap_intc_class_init(ObjectClass *klass, void *data)
 406{
 407    DeviceClass *dc = DEVICE_CLASS(klass);
 408
 409    dc->reset = omap_inth_reset;
 410    device_class_set_props(dc, omap_intc_properties);
 411    /* Reason: pointer property "clk" */
 412    dc->user_creatable = false;
 413    dc->realize = omap_intc_realize;
 414}
 415
 416static const TypeInfo omap_intc_info = {
 417    .name          = "omap-intc",
 418    .parent        = TYPE_OMAP_INTC,
 419    .instance_init = omap_intc_init,
 420    .class_init    = omap_intc_class_init,
 421};
 422
 423static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
 424                                unsigned size)
 425{
 426    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
 427    int offset = addr;
 428    int bank_no, line_no;
 429    struct omap_intr_handler_bank_s *bank = NULL;
 430
 431    if ((offset & 0xf80) == 0x80) {
 432        bank_no = (offset & 0x60) >> 5;
 433        if (bank_no < s->nbanks) {
 434            offset &= ~0x60;
 435            bank = &s->bank[bank_no];
 436        } else {
 437            OMAP_BAD_REG(addr);
 438            return 0;
 439        }
 440    }
 441
 442    switch (offset) {
 443    case 0x00:  /* INTC_REVISION */
 444        return s->revision;
 445
 446    case 0x10:  /* INTC_SYSCONFIG */
 447        return (s->autoidle >> 2) & 1;
 448
 449    case 0x14:  /* INTC_SYSSTATUS */
 450        return 1;                                               /* RESETDONE */
 451
 452    case 0x40:  /* INTC_SIR_IRQ */
 453        return s->sir_intr[0];
 454
 455    case 0x44:  /* INTC_SIR_FIQ */
 456        return s->sir_intr[1];
 457
 458    case 0x48:  /* INTC_CONTROL */
 459        return (!s->mask) << 2;                                 /* GLOBALMASK */
 460
 461    case 0x4c:  /* INTC_PROTECTION */
 462        return 0;
 463
 464    case 0x50:  /* INTC_IDLE */
 465        return s->autoidle & 3;
 466
 467    /* Per-bank registers */
 468    case 0x80:  /* INTC_ITR */
 469        return bank->inputs;
 470
 471    case 0x84:  /* INTC_MIR */
 472        return bank->mask;
 473
 474    case 0x88:  /* INTC_MIR_CLEAR */
 475    case 0x8c:  /* INTC_MIR_SET */
 476        return 0;
 477
 478    case 0x90:  /* INTC_ISR_SET */
 479        return bank->swi;
 480
 481    case 0x94:  /* INTC_ISR_CLEAR */
 482        return 0;
 483
 484    case 0x98:  /* INTC_PENDING_IRQ */
 485        return bank->irqs & ~bank->mask & ~bank->fiq;
 486
 487    case 0x9c:  /* INTC_PENDING_FIQ */
 488        return bank->irqs & ~bank->mask & bank->fiq;
 489
 490    /* Per-line registers */
 491    case 0x100 ... 0x300:       /* INTC_ILR */
 492        bank_no = (offset - 0x100) >> 7;
 493        if (bank_no > s->nbanks)
 494            break;
 495        bank = &s->bank[bank_no];
 496        line_no = (offset & 0x7f) >> 2;
 497        return (bank->priority[line_no] << 2) |
 498                ((bank->fiq >> line_no) & 1);
 499    }
 500    OMAP_BAD_REG(addr);
 501    return 0;
 502}
 503
 504static void omap2_inth_write(void *opaque, hwaddr addr,
 505                             uint64_t value, unsigned size)
 506{
 507    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
 508    int offset = addr;
 509    int bank_no, line_no;
 510    struct omap_intr_handler_bank_s *bank = NULL;
 511
 512    if ((offset & 0xf80) == 0x80) {
 513        bank_no = (offset & 0x60) >> 5;
 514        if (bank_no < s->nbanks) {
 515            offset &= ~0x60;
 516            bank = &s->bank[bank_no];
 517        } else {
 518            OMAP_BAD_REG(addr);
 519            return;
 520        }
 521    }
 522
 523    switch (offset) {
 524    case 0x10:  /* INTC_SYSCONFIG */
 525        s->autoidle &= 4;
 526        s->autoidle |= (value & 1) << 2;
 527        if (value & 2) {                                        /* SOFTRESET */
 528            omap_inth_reset(DEVICE(s));
 529        }
 530        return;
 531
 532    case 0x48:  /* INTC_CONTROL */
 533        s->mask = (value & 4) ? 0 : ~0;                         /* GLOBALMASK */
 534        if (value & 2) {                                        /* NEWFIQAGR */
 535            qemu_set_irq(s->parent_intr[1], 0);
 536            s->new_agr[1] = ~0;
 537            omap_inth_update(s, 1);
 538        }
 539        if (value & 1) {                                        /* NEWIRQAGR */
 540            qemu_set_irq(s->parent_intr[0], 0);
 541            s->new_agr[0] = ~0;
 542            omap_inth_update(s, 0);
 543        }
 544        return;
 545
 546    case 0x4c:  /* INTC_PROTECTION */
 547        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
 548         * for every register, see Chapter 3 and 4 for privileged mode.  */
 549        if (value & 1)
 550            fprintf(stderr, "%s: protection mode enable attempt\n",
 551                            __func__);
 552        return;
 553
 554    case 0x50:  /* INTC_IDLE */
 555        s->autoidle &= ~3;
 556        s->autoidle |= value & 3;
 557        return;
 558
 559    /* Per-bank registers */
 560    case 0x84:  /* INTC_MIR */
 561        bank->mask = value;
 562        omap_inth_update(s, 0);
 563        omap_inth_update(s, 1);
 564        return;
 565
 566    case 0x88:  /* INTC_MIR_CLEAR */
 567        bank->mask &= ~value;
 568        omap_inth_update(s, 0);
 569        omap_inth_update(s, 1);
 570        return;
 571
 572    case 0x8c:  /* INTC_MIR_SET */
 573        bank->mask |= value;
 574        return;
 575
 576    case 0x90:  /* INTC_ISR_SET */
 577        bank->irqs |= bank->swi |= value;
 578        omap_inth_update(s, 0);
 579        omap_inth_update(s, 1);
 580        return;
 581
 582    case 0x94:  /* INTC_ISR_CLEAR */
 583        bank->swi &= ~value;
 584        bank->irqs = bank->swi & bank->inputs;
 585        return;
 586
 587    /* Per-line registers */
 588    case 0x100 ... 0x300:       /* INTC_ILR */
 589        bank_no = (offset - 0x100) >> 7;
 590        if (bank_no > s->nbanks)
 591            break;
 592        bank = &s->bank[bank_no];
 593        line_no = (offset & 0x7f) >> 2;
 594        bank->priority[line_no] = (value >> 2) & 0x3f;
 595        bank->fiq &= ~(1 << line_no);
 596        bank->fiq |= (value & 1) << line_no;
 597        return;
 598
 599    case 0x00:  /* INTC_REVISION */
 600    case 0x14:  /* INTC_SYSSTATUS */
 601    case 0x40:  /* INTC_SIR_IRQ */
 602    case 0x44:  /* INTC_SIR_FIQ */
 603    case 0x80:  /* INTC_ITR */
 604    case 0x98:  /* INTC_PENDING_IRQ */
 605    case 0x9c:  /* INTC_PENDING_FIQ */
 606        OMAP_RO_REG(addr);
 607        return;
 608    }
 609    OMAP_BAD_REG(addr);
 610}
 611
 612static const MemoryRegionOps omap2_inth_mem_ops = {
 613    .read = omap2_inth_read,
 614    .write = omap2_inth_write,
 615    .endianness = DEVICE_NATIVE_ENDIAN,
 616    .valid = {
 617        .min_access_size = 4,
 618        .max_access_size = 4,
 619    },
 620};
 621
 622static void omap2_intc_init(Object *obj)
 623{
 624    DeviceState *dev = DEVICE(obj);
 625    struct omap_intr_handler_s *s = OMAP_INTC(obj);
 626    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 627
 628    s->level_only = 1;
 629    s->nbanks = 3;
 630    sysbus_init_irq(sbd, &s->parent_intr[0]);
 631    sysbus_init_irq(sbd, &s->parent_intr[1]);
 632    qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
 633    memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
 634                          "omap2-intc", 0x1000);
 635    sysbus_init_mmio(sbd, &s->mmio);
 636}
 637
 638static void omap2_intc_realize(DeviceState *dev, Error **errp)
 639{
 640    struct omap_intr_handler_s *s = OMAP_INTC(dev);
 641
 642    if (!s->iclk) {
 643        error_setg(errp, "omap2-intc: iclk not connected");
 644        return;
 645    }
 646    if (!s->fclk) {
 647        error_setg(errp, "omap2-intc: fclk not connected");
 648        return;
 649    }
 650}
 651
 652static Property omap2_intc_properties[] = {
 653    DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
 654    revision, 0x21),
 655    DEFINE_PROP_END_OF_LIST(),
 656};
 657
 658static void omap2_intc_class_init(ObjectClass *klass, void *data)
 659{
 660    DeviceClass *dc = DEVICE_CLASS(klass);
 661
 662    dc->reset = omap_inth_reset;
 663    device_class_set_props(dc, omap2_intc_properties);
 664    /* Reason: pointer property "iclk", "fclk" */
 665    dc->user_creatable = false;
 666    dc->realize = omap2_intc_realize;
 667}
 668
 669static const TypeInfo omap2_intc_info = {
 670    .name          = "omap2-intc",
 671    .parent        = TYPE_OMAP_INTC,
 672    .instance_init = omap2_intc_init,
 673    .class_init    = omap2_intc_class_init,
 674};
 675
 676static const TypeInfo omap_intc_type_info = {
 677    .name          = TYPE_OMAP_INTC,
 678    .parent        = TYPE_SYS_BUS_DEVICE,
 679    .instance_size = sizeof(omap_intr_handler),
 680    .abstract      = true,
 681};
 682
 683static void omap_intc_register_types(void)
 684{
 685    type_register_static(&omap_intc_type_info);
 686    type_register_static(&omap_intc_info);
 687    type_register_static(&omap2_intc_info);
 688}
 689
 690type_init(omap_intc_register_types)
 691