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