qemu/hw/intc/xilinx_intc.c
<<
>>
Prefs
   1/*
   2 * QEMU Xilinx OPB Interrupt Controller.
   3 *
   4 * Copyright (c) 2009 Edgar E. Iglesias.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "hw/sysbus.h"
  27#include "qemu/module.h"
  28#include "hw/hw.h"
  29
  30#define D(x)
  31
  32#define R_ISR       0
  33#define R_IPR       1
  34#define R_IER       2
  35#define R_IAR       3
  36#define R_SIE       4
  37#define R_CIE       5
  38#define R_IVR       6
  39#define R_MER       7
  40#define R_MAX       8
  41
  42#define TYPE_XILINX_INTC "xlnx.xps-intc"
  43#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC)
  44
  45struct xlx_pic
  46{
  47    SysBusDevice parent_obj;
  48
  49    MemoryRegion mmio;
  50    qemu_irq parent_irq;
  51
  52    /* Configuration reg chosen at synthesis-time. QEMU populates
  53       the bits at board-setup.  */
  54    uint32_t c_kind_of_intr;
  55
  56    /* Runtime control registers.  */
  57    uint32_t regs[R_MAX];
  58    /* state of the interrupt input pins */
  59    uint32_t irq_pin_state;
  60};
  61
  62static void update_irq(struct xlx_pic *p)
  63{
  64    uint32_t i;
  65
  66    /* level triggered interrupt */
  67    if (p->regs[R_MER] & 2) {
  68        p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
  69    }
  70
  71    /* Update the pending register.  */
  72    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
  73
  74    /* Update the vector register.  */
  75    for (i = 0; i < 32; i++) {
  76        if (p->regs[R_IPR] & (1U << i)) {
  77            break;
  78        }
  79    }
  80    if (i == 32)
  81        i = ~0;
  82
  83    p->regs[R_IVR] = i;
  84    qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
  85}
  86
  87static uint64_t
  88pic_read(void *opaque, hwaddr addr, unsigned int size)
  89{
  90    struct xlx_pic *p = opaque;
  91    uint32_t r = 0;
  92
  93    addr >>= 2;
  94    switch (addr)
  95    {
  96        default:
  97            if (addr < ARRAY_SIZE(p->regs))
  98                r = p->regs[addr];
  99            break;
 100
 101    }
 102    D(printf("%s %x=%x\n", __func__, addr * 4, r));
 103    return r;
 104}
 105
 106static void
 107pic_write(void *opaque, hwaddr addr,
 108          uint64_t val64, unsigned int size)
 109{
 110    struct xlx_pic *p = opaque;
 111    uint32_t value = val64;
 112
 113    addr >>= 2;
 114    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
 115    switch (addr) 
 116    {
 117        case R_IAR:
 118            p->regs[R_ISR] &= ~value; /* ACK.  */
 119            break;
 120        case R_SIE:
 121            p->regs[R_IER] |= value;  /* Atomic set ie.  */
 122            break;
 123        case R_CIE:
 124            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
 125            break;
 126        case R_MER:
 127            p->regs[R_MER] = value & 0x3;
 128            break;
 129        case R_ISR:
 130            if ((p->regs[R_MER] & 2)) {
 131                break;
 132            }
 133            /* fallthrough */
 134        default:
 135            if (addr < ARRAY_SIZE(p->regs))
 136                p->regs[addr] = value;
 137            break;
 138    }
 139    update_irq(p);
 140}
 141
 142static const MemoryRegionOps pic_ops = {
 143    .read = pic_read,
 144    .write = pic_write,
 145    .endianness = DEVICE_NATIVE_ENDIAN,
 146    .valid = {
 147        .min_access_size = 4,
 148        .max_access_size = 4
 149    }
 150};
 151
 152static void irq_handler(void *opaque, int irq, int level)
 153{
 154    struct xlx_pic *p = opaque;
 155
 156    /* edge triggered interrupt */
 157    if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
 158        p->regs[R_ISR] |= (level << irq);
 159    }
 160
 161    p->irq_pin_state &= ~(1 << irq);
 162    p->irq_pin_state |= level << irq;
 163    update_irq(p);
 164}
 165
 166static void xilinx_intc_init(Object *obj)
 167{
 168    struct xlx_pic *p = XILINX_INTC(obj);
 169
 170    qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
 171    sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
 172
 173    memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
 174                          R_MAX * 4);
 175    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
 176}
 177
 178static Property xilinx_intc_properties[] = {
 179    DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
 180    DEFINE_PROP_END_OF_LIST(),
 181};
 182
 183static void xilinx_intc_class_init(ObjectClass *klass, void *data)
 184{
 185    DeviceClass *dc = DEVICE_CLASS(klass);
 186
 187    dc->props = xilinx_intc_properties;
 188}
 189
 190static const TypeInfo xilinx_intc_info = {
 191    .name          = TYPE_XILINX_INTC,
 192    .parent        = TYPE_SYS_BUS_DEVICE,
 193    .instance_size = sizeof(struct xlx_pic),
 194    .instance_init = xilinx_intc_init,
 195    .class_init    = xilinx_intc_class_init,
 196};
 197
 198static void xilinx_intc_register_types(void)
 199{
 200    type_register_static(&xilinx_intc_info);
 201}
 202
 203type_init(xilinx_intc_register_types)
 204