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 "hw/hw.h"
  28
  29#define D(x)
  30
  31#define R_ISR       0
  32#define R_IPR       1
  33#define R_IER       2
  34#define R_IAR       3
  35#define R_SIE       4
  36#define R_CIE       5
  37#define R_IVR       6
  38#define R_MER       7
  39#define R_MAX       8
  40
  41#define TYPE_XILINX_INTC "xlnx.xps-intc"
  42#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC)
  43
  44struct xlx_pic
  45{
  46    SysBusDevice parent_obj;
  47
  48    MemoryRegion mmio;
  49    qemu_irq parent_irq;
  50
  51    /* Configuration reg chosen at synthesis-time. QEMU populates
  52       the bits at board-setup.  */
  53    uint32_t c_kind_of_intr;
  54
  55    /* Runtime control registers.  */
  56    uint32_t regs[R_MAX];
  57    /* state of the interrupt input pins */
  58    uint32_t irq_pin_state;
  59};
  60
  61static void update_irq(struct xlx_pic *p)
  62{
  63    uint32_t i;
  64
  65    /* level triggered interrupt */
  66    if (p->regs[R_MER] & 2) {
  67        p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
  68    }
  69
  70    /* Update the pending register.  */
  71    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
  72
  73    /* Update the vector register.  */
  74    for (i = 0; i < 32; i++) {
  75        if (p->regs[R_IPR] & (1U << i)) {
  76            break;
  77        }
  78    }
  79    if (i == 32)
  80        i = ~0;
  81
  82    p->regs[R_IVR] = i;
  83    qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
  84}
  85
  86static uint64_t
  87pic_read(void *opaque, hwaddr addr, unsigned int size)
  88{
  89    struct xlx_pic *p = opaque;
  90    uint32_t r = 0;
  91
  92    addr >>= 2;
  93    switch (addr)
  94    {
  95        default:
  96            if (addr < ARRAY_SIZE(p->regs))
  97                r = p->regs[addr];
  98            break;
  99
 100    }
 101    D(printf("%s %x=%x\n", __func__, addr * 4, r));
 102    return r;
 103}
 104
 105static void
 106pic_write(void *opaque, hwaddr addr,
 107          uint64_t val64, unsigned int size)
 108{
 109    struct xlx_pic *p = opaque;
 110    uint32_t value = val64;
 111
 112    addr >>= 2;
 113    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
 114    switch (addr) 
 115    {
 116        case R_IAR:
 117            p->regs[R_ISR] &= ~value; /* ACK.  */
 118            break;
 119        case R_SIE:
 120            p->regs[R_IER] |= value;  /* Atomic set ie.  */
 121            break;
 122        case R_CIE:
 123            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
 124            break;
 125        case R_MER:
 126            p->regs[R_MER] = value & 0x3;
 127            break;
 128        case R_ISR:
 129            if ((p->regs[R_MER] & 2)) {
 130                break;
 131            }
 132            /* fallthrough */
 133        default:
 134            if (addr < ARRAY_SIZE(p->regs))
 135                p->regs[addr] = value;
 136            break;
 137    }
 138    update_irq(p);
 139}
 140
 141static const MemoryRegionOps pic_ops = {
 142    .read = pic_read,
 143    .write = pic_write,
 144    .endianness = DEVICE_NATIVE_ENDIAN,
 145    .valid = {
 146        .min_access_size = 4,
 147        .max_access_size = 4
 148    }
 149};
 150
 151static void irq_handler(void *opaque, int irq, int level)
 152{
 153    struct xlx_pic *p = opaque;
 154
 155    /* edge triggered interrupt */
 156    if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
 157        p->regs[R_ISR] |= (level << irq);
 158    }
 159
 160    p->irq_pin_state &= ~(1 << irq);
 161    p->irq_pin_state |= level << irq;
 162    update_irq(p);
 163}
 164
 165static void xilinx_intc_init(Object *obj)
 166{
 167    struct xlx_pic *p = XILINX_INTC(obj);
 168
 169    qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
 170    sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
 171
 172    memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
 173                          R_MAX * 4);
 174    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
 175}
 176
 177static Property xilinx_intc_properties[] = {
 178    DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
 179    DEFINE_PROP_END_OF_LIST(),
 180};
 181
 182static void xilinx_intc_class_init(ObjectClass *klass, void *data)
 183{
 184    DeviceClass *dc = DEVICE_CLASS(klass);
 185
 186    dc->props = xilinx_intc_properties;
 187}
 188
 189static const TypeInfo xilinx_intc_info = {
 190    .name          = TYPE_XILINX_INTC,
 191    .parent        = TYPE_SYS_BUS_DEVICE,
 192    .instance_size = sizeof(struct xlx_pic),
 193    .instance_init = xilinx_intc_init,
 194    .class_init    = xilinx_intc_class_init,
 195};
 196
 197static void xilinx_intc_register_types(void)
 198{
 199    type_register_static(&xilinx_intc_info);
 200}
 201
 202type_init(xilinx_intc_register_types)
 203