qemu/hw/intc/xilinx_iomod_intc.c
<<
>>
Prefs
   1/*
   2 * QEMU model of Xilinx I/O Module Interrupt Controller
   3 *
   4 * Copyright (c) 2013 Xilinx Inc
   5 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "hw/sysbus.h"
  28#include "hw/register.h"
  29#include "qemu/log.h"
  30#include "hw/fdt_generic_util.h"
  31
  32#ifndef XILINX_IO_MODULE_INTC_ERR_DEBUG
  33#define XILINX_IO_MODULE_INTC_ERR_DEBUG 0
  34#endif
  35
  36#define TYPE_XILINX_IO_MODULE_INTC "xlnx.io_intc"
  37
  38#define XILINX_IO_MODULE_INTC(obj) \
  39     OBJECT_CHECK(XilinxIntC, (obj), TYPE_XILINX_IO_MODULE_INTC)
  40
  41#define DB_PRINT_L(lvl, fmt, args...) do {\
  42    if (XILINX_IO_MODULE_INTC_ERR_DEBUG >= (lvl)) {\
  43        qemu_log(TYPE_XILINX_IO_MODULE_INTC ": %s: " fmt, __func__, ## args);\
  44    } \
  45} while (0);
  46
  47#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
  48
  49
  50#define R_IOM_IRQ_MODE              (0x00 / 4)
  51
  52#define R_MAX_0                     (1)
  53
  54#define R_IOM_IRQ_STATUS            (0x00 / 4)
  55#define R_IOM_IRQ_PENDING           (0x04 / 4)
  56#define R_IOM_IRQ_ENABLE            (0x08 / 4)
  57#define R_IOM_IRQ_ACK               (0x0C / 4)
  58
  59#define IOM_IRQF_PIT1_SHIFT         3
  60#define IOM_IRQF_PIT2_SHIFT         4
  61#define IOM_IRQF_PIT3_SHIFT         5
  62#define IOM_IRQF_PIT4_SHIFT         6
  63
  64#define IOM_IRQF_UART_ERR           (1 << 0)
  65#define IOM_IRQF_UART_TX            (1 << 1)
  66#define IOM_IRQF_UART_RX            (1 << 2)
  67#define IOM_IRQF_PIT1               (1 << IOM_IRQF_PIT1_SHIFT)
  68#define IOM_IRQF_PIT2               (1 << IOM_IRQF_PIT2_SHIFT)
  69#define IOM_IRQF_PIT3               (1 << IOM_IRQF_PIT3_SHIFT)
  70#define IOM_IRQF_PIT4               (1 << IOM_IRQF_PIT4_SHIFT)
  71#define IOM_IRQF_FIT1               (1 << 7)
  72#define IOM_IRQF_FIT2               (1 << 8)
  73#define IOM_IRQF_FIT3               (1 << 9)
  74#define IOM_IRQF_FIT4               (1 << 10)
  75#define IOM_IRQF_GPI1               (1 << 11)
  76#define IOM_IRQF_GPI2               (1 << 12)
  77#define IOM_IRQF_GPI3               (1 << 13)
  78#define IOM_IRQF_GPI4               (1 << 14)
  79#define IOM_IRQF_EXT0               (1 << 16)
  80
  81#define R_MAX_1                     (R_IOM_IRQ_ACK + 1)
  82
  83#define R_IOM_IRQ_VECTOR0           (0x00 / 4)
  84#define R_IOM_IRQ_VECTOR1           (0x04 / 4)
  85#define R_IOM_IRQ_VECTOR2           (0x08 / 4)
  86#define R_IOM_IRQ_VECTOR3           (0x0C / 4)
  87#define R_IOM_IRQ_VECTOR4           (0x10 / 4)
  88#define R_IOM_IRQ_VECTOR5           (0x14 / 4)
  89#define R_IOM_IRQ_VECTOR6           (0x18 / 4)
  90#define R_IOM_IRQ_VECTOR7           (0x1C / 4)
  91#define R_IOM_IRQ_VECTOR8           (0x20 / 4)
  92#define R_IOM_IRQ_VECTOR9           (0x24 / 4)
  93#define R_IOM_IRQ_VECTOR10          (0x28 / 4)
  94#define R_IOM_IRQ_VECTOR11          (0x2C / 4)
  95#define R_IOM_IRQ_VECTOR12          (0x30 / 4)
  96#define R_IOM_IRQ_VECTOR13          (0x34 / 4)
  97#define R_IOM_IRQ_VECTOR14          (0x38 / 4)
  98#define R_IOM_IRQ_VECTOR15          (0x3C / 4)
  99#define R_IOM_IRQ_VECTOR16          (0x40 / 4)
 100#define R_IOM_IRQ_VECTOR17          (0x44 / 4)
 101#define R_IOM_IRQ_VECTOR18          (0x48 / 4)
 102#define R_IOM_IRQ_VECTOR19          (0x4C / 4)
 103#define R_IOM_IRQ_VECTOR20          (0x50 / 4)
 104#define R_IOM_IRQ_VECTOR21          (0x54 / 4)
 105#define R_IOM_IRQ_VECTOR22          (0x58 / 4)
 106#define R_IOM_IRQ_VECTOR23          (0x5C / 4)
 107#define R_IOM_IRQ_VECTOR24          (0x60 / 4)
 108#define R_IOM_IRQ_VECTOR25          (0x64 / 4)
 109#define R_IOM_IRQ_VECTOR26          (0x68 / 4)
 110#define R_IOM_IRQ_VECTOR27          (0x6C / 4)
 111#define R_IOM_IRQ_VECTOR28          (0x70 / 4)
 112#define R_IOM_IRQ_VECTOR29          (0x74 / 4)
 113#define R_IOM_IRQ_VECTOR30          (0x78 / 4)
 114#define R_IOM_IRQ_VECTOR31          (0x7C / 4)
 115
 116#define R_MAX_2                     (0x80 / 4)
 117
 118typedef struct XilinxIntC {
 119    SysBusDevice parent_obj;
 120    MemoryRegion iomem[3];
 121    qemu_irq parent_irq;
 122
 123    struct {
 124        bool use_ext_intr;
 125        uint32_t intr_size;
 126        uint32_t level_edge;
 127        uint32_t positive;
 128        bool has_fast;
 129        uint32_t addr_width;
 130        uint32_t base_vectors;
 131    } cfg;
 132
 133    uint32_t irq_raw;
 134    uint32_t irq_mode;
 135    uint32_t regs[R_MAX_1];
 136    uint32_t vectors[R_MAX_1];
 137    RegisterInfo regs_info0[R_MAX_0];
 138    RegisterInfo regs_info1[R_MAX_1];
 139    RegisterInfo regs_info2[R_MAX_2];
 140    RegisterInfo *regs_infos[3];
 141    const char *prefix;
 142    /* Debug only */
 143    bool irq_output;
 144} XilinxIntC;
 145
 146static Property xlx_iom_properties[] = {
 147    DEFINE_PROP_BOOL("intc-use-ext-intr", XilinxIntC, cfg.use_ext_intr, 0),
 148    DEFINE_PROP_UINT32("intc-intr-size", XilinxIntC, cfg.intr_size, 0),
 149    DEFINE_PROP_UINT32("intc-level-edge", XilinxIntC, cfg.level_edge, 0),
 150    DEFINE_PROP_UINT32("intc-positive", XilinxIntC, cfg.positive, 0),
 151    DEFINE_PROP_BOOL("intc-has-fast", XilinxIntC, cfg.has_fast, 0),
 152    DEFINE_PROP_UINT32("intc-addr-width", XilinxIntC, cfg.addr_width, 32),
 153    DEFINE_PROP_UINT32("intc-base-vectors", XilinxIntC, cfg.base_vectors, 0),
 154    DEFINE_PROP_END_OF_LIST(),
 155};
 156
 157static void iom_intc_irq_ack(RegisterInfo *reg, uint64_t val64);
 158static void iom_intc_update(RegisterInfo *reg, uint64_t val64);
 159
 160static void xlx_iom_irq_update(XilinxIntC *s)
 161{
 162    bool old_state = s->irq_output;
 163
 164    s->regs[R_IOM_IRQ_PENDING] = s->regs[R_IOM_IRQ_STATUS];
 165    s->regs[R_IOM_IRQ_PENDING] &= s->regs[R_IOM_IRQ_ENABLE];
 166    s->irq_output = s->regs[R_IOM_IRQ_PENDING];
 167    DB_PRINT_L(s->irq_output != old_state ? 1 : 2, "Setting IRQ output = %d\n",
 168               (int)s->irq_output);
 169    qemu_set_irq(s->parent_irq, s->irq_output);
 170}
 171
 172static void iom_intc_irq_ack(RegisterInfo *reg, uint64_t val64)
 173{
 174    XilinxIntC *s = XILINX_IO_MODULE_INTC(reg->opaque);
 175    uint32_t val = val64;
 176    /* Only clear.  */
 177    val &= s->regs[R_IOM_IRQ_STATUS];
 178    s->regs[R_IOM_IRQ_STATUS] ^= val;
 179
 180    /* Active level triggered interrupts stay high.  */
 181    s->regs[R_IOM_IRQ_STATUS] |= s->irq_raw & ~s->cfg.level_edge;
 182
 183    xlx_iom_irq_update(s);
 184}
 185
 186static void iom_intc_update(RegisterInfo *reg, uint64_t val64)
 187{
 188    XilinxIntC *s = XILINX_IO_MODULE_INTC(reg->opaque);
 189    xlx_iom_irq_update(s);
 190}
 191
 192static const MemoryRegionOps iom_intc_ops = {
 193    .read = register_read_memory_le,
 194    .write = register_write_memory_le,
 195    .endianness = DEVICE_LITTLE_ENDIAN,
 196    .valid = {
 197        .min_access_size = 4,
 198        .max_access_size = 4,
 199    },
 200};
 201
 202static void irq_handler(void *opaque, int irq, int level)
 203{
 204    XilinxIntC *s = XILINX_IO_MODULE_INTC(opaque);
 205    uint32_t mask = 1 << irq;
 206    uint32_t flip = (~s->cfg.positive) & mask;
 207    uint32_t prev = s->irq_raw;
 208    uint32_t p;
 209
 210    s->irq_raw &= ~(1 << irq);
 211    s->irq_raw |= (!!level) << irq;
 212
 213    /* Turn active-low into active-high.  */
 214    s->irq_raw ^= flip;
 215
 216    DB_PRINT_L(prev ^ s->irq_raw ? 1 : 2, "Input irq %d = %d\n", irq, level);
 217
 218    if (s->cfg.level_edge & (1 << irq)) {
 219        /* Edge triggered.  */
 220        p = (prev ^ s->irq_raw) & s->irq_raw & mask;
 221    } else {
 222        /* Level triggered.  */
 223        p = s->irq_raw & mask;
 224    }
 225    s->regs[R_IOM_IRQ_STATUS] |= p;
 226    xlx_iom_irq_update(s);
 227}
 228
 229static const RegisterAccessInfo intc_regs_info0[] = {
 230    [R_IOM_IRQ_MODE] = { .name = "IRQ_MODE" },
 231};
 232
 233static const RegisterAccessInfo intc_regs_info1[] = {
 234    [R_IOM_IRQ_STATUS] = { .name = "IRQ_STATUS", .ro = ~0 },
 235    [R_IOM_IRQ_PENDING] = { .name = "IRQ_PENDING" , .ro = ~0 },
 236    [R_IOM_IRQ_ENABLE] = { .name = "IRQ_ENABLE",
 237                           .post_write = iom_intc_update },
 238    [R_IOM_IRQ_ACK] = { .name = "IRQ_ACK", .post_write = iom_intc_irq_ack },
 239};
 240
 241static const RegisterAccessInfo intc_regs_info2[] = {
 242#define REG_VECTOR(n) [R_IOM_IRQ_VECTOR ## n] =                            \
 243    { .name  = "IRQ_VECTOR" #n,                                            \
 244      .ui1 = (RegisterAccessError[]) {                                     \
 245             { .mask = ~0, .reason = "IRQ Vectors not implemented" }, {} } }
 246
 247    REG_VECTOR(0),
 248    REG_VECTOR(1),
 249    REG_VECTOR(2),
 250    REG_VECTOR(3),
 251    REG_VECTOR(4),
 252    REG_VECTOR(5),
 253    REG_VECTOR(6),
 254    REG_VECTOR(7),
 255    REG_VECTOR(8),
 256    REG_VECTOR(9),
 257    REG_VECTOR(10),
 258    REG_VECTOR(11),
 259    REG_VECTOR(12),
 260    REG_VECTOR(13),
 261    REG_VECTOR(14),
 262    REG_VECTOR(15),
 263    REG_VECTOR(16),
 264    REG_VECTOR(17),
 265    REG_VECTOR(18),
 266    REG_VECTOR(19),
 267    REG_VECTOR(20),
 268    REG_VECTOR(21),
 269    REG_VECTOR(22),
 270    REG_VECTOR(23),
 271    REG_VECTOR(24),
 272    REG_VECTOR(25),
 273    REG_VECTOR(26),
 274    REG_VECTOR(27),
 275    REG_VECTOR(28),
 276    REG_VECTOR(29),
 277    REG_VECTOR(30),
 278    REG_VECTOR(31),
 279};
 280
 281static const RegisterAccessInfo *intc_reginfos[] = {
 282    &intc_regs_info0[0], &intc_regs_info1[0], &intc_regs_info2[0]
 283};
 284
 285static const unsigned int intc_reginfo_sizes[] = {
 286    ARRAY_SIZE(intc_regs_info0),
 287    ARRAY_SIZE(intc_regs_info1),
 288    ARRAY_SIZE(intc_regs_info2),
 289};
 290
 291
 292static void iom_intc_reset(DeviceState *dev)
 293{
 294    XilinxIntC *s = XILINX_IO_MODULE_INTC(dev);
 295    unsigned int i;
 296    unsigned int rmap;
 297
 298    for (rmap = 0; rmap < ARRAY_SIZE(intc_reginfos); rmap++) {
 299        for (i = 0; i < intc_reginfo_sizes[rmap]; ++i) {
 300            register_reset(&s->regs_infos[rmap][i]);
 301        }
 302    }
 303}
 304
 305static void xlx_iom_realize(DeviceState *dev, Error **errp)
 306{
 307    XilinxIntC *s = XILINX_IO_MODULE_INTC(dev);
 308    unsigned int i;
 309    unsigned int rmap;
 310    uint32_t *regmaps[3] = {
 311        &s->irq_mode, &s->regs[0], &s->vectors[0]
 312    };
 313    s->prefix = object_get_canonical_path(OBJECT(dev));
 314    /* Internal interrupts are edge triggered?  */
 315    s->cfg.level_edge <<= 16;
 316    s->cfg.level_edge |= 0xffff;
 317    /* Internal interrupts are postitive.  */
 318    s->cfg.positive <<= 16;
 319    s->cfg.positive |= 0xffff;
 320    /* Max 16 external interrupts.  */
 321    assert(s->cfg.intr_size <= 16);
 322
 323    for (rmap = 0; rmap < ARRAY_SIZE(intc_reginfos); rmap++) {
 324        for (i = 0; i < intc_reginfo_sizes[rmap]; ++i) {
 325            RegisterInfo *r = &s->regs_infos[rmap][i];
 326
 327            *r = (RegisterInfo) {
 328                .data = (uint8_t *)&regmaps[rmap][i],
 329                .data_size = sizeof(uint32_t),
 330                .access = &intc_reginfos[rmap][i],
 331                .debug = XILINX_IO_MODULE_INTC_ERR_DEBUG,
 332                .prefix = s->prefix,
 333                .opaque = s,
 334            };
 335            memory_region_init_io(&r->mem, OBJECT(dev), &iom_intc_ops, r,
 336                                  r->access->name, 4);
 337            memory_region_add_subregion(&s->iomem[rmap], i * 4, &r->mem);
 338        }
 339    }
 340    qdev_init_gpio_in(dev, irq_handler, 16 + s->cfg.intr_size);
 341}
 342
 343static void xlx_iom_init(Object *obj)
 344{
 345    XilinxIntC *s = XILINX_IO_MODULE_INTC(obj);
 346    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 347    unsigned int i;
 348
 349    s->regs_infos[0] = s->regs_info0;
 350    s->regs_infos[1] = s->regs_info1;
 351    s->regs_infos[2] = s->regs_info2;
 352
 353    for (i = 0; i < ARRAY_SIZE(s->iomem); i++) {
 354        char *region_name = g_strdup_printf("%s-%d", TYPE_XILINX_IO_MODULE_INTC,
 355                                            i);
 356        memory_region_init_io(&s->iomem[i], obj, &iom_intc_ops, s,
 357                              region_name, intc_reginfo_sizes[i] * 4);
 358        g_free(region_name);
 359        sysbus_init_mmio(sbd, &s->iomem[i]);
 360    }
 361    qdev_init_gpio_out(DEVICE(obj), &s->parent_irq, 1);
 362}
 363
 364static int xilinx_iom_fdt_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
 365                                  uint32_t *cells, int ncells, int max,
 366                                  Error **errp)
 367{
 368    /* FIXME: Add Error checking */
 369    (*irqs) = qdev_get_gpio_in(DEVICE(obj), cells[0]);
 370    return 1;
 371};
 372
 373static const VMStateDescription vmstate_xlx_iom = {
 374    .name = TYPE_XILINX_IO_MODULE_INTC,
 375    .version_id = 1,
 376    .minimum_version_id = 1,
 377    .minimum_version_id_old = 1,
 378    .fields = (VMStateField[]) {
 379        VMSTATE_END_OF_LIST(),
 380    }
 381};
 382
 383static void xlx_iom_class_init(ObjectClass *klass, void *data)
 384{
 385    DeviceClass *dc = DEVICE_CLASS(klass);
 386    FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(klass);
 387
 388    dc->reset = iom_intc_reset;
 389    dc->realize = xlx_iom_realize;
 390    dc->props = xlx_iom_properties;
 391    dc->vmsd = &vmstate_xlx_iom;
 392    fgic->get_irq = xilinx_iom_fdt_get_irq;
 393}
 394
 395static const TypeInfo xlx_iom_info = {
 396    .name          = TYPE_XILINX_IO_MODULE_INTC,
 397    .parent        = TYPE_SYS_BUS_DEVICE,
 398    .instance_size = sizeof(XilinxIntC),
 399    .class_init    = xlx_iom_class_init,
 400    .instance_init = xlx_iom_init,
 401    .interfaces = (InterfaceInfo[]) {
 402        { TYPE_FDT_GENERIC_INTC },
 403        { }
 404    },
 405};
 406
 407static void xlx_iom_register_types(void)
 408{
 409    type_register_static(&xlx_iom_info);
 410}
 411
 412type_init(xlx_iom_register_types)
 413