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 "qapi/error.h"
  28#include "hw/hw.h"
  29#include "qom/cpu.h"
  30#include "hw/fdt_generic_util.h"
  31
  32#define D(x)
  33
  34#define R_ISR       0
  35#define R_IPR       1
  36#define R_IER       2
  37#define R_IAR       3
  38#define R_SIE       4
  39#define R_CIE       5
  40#define R_IVR       6
  41#define R_MER       7
  42#define R_MAX       8
  43
  44#define TYPE_XILINX_INTC "xlnx.xps-intc"
  45#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC)
  46
  47struct xlx_pic
  48{
  49    SysBusDevice parent_obj;
  50
  51    MemoryRegion mmio;
  52    qemu_irq parent_irq;
  53
  54    /* Configuration reg chosen at synthesis-time. QEMU populates
  55       the bits at board-setup.  */
  56    uint32_t c_kind_of_intr;
  57
  58    /* Runtime control registers.  */
  59    uint32_t regs[R_MAX];
  60    /* state of the interrupt input pins */
  61    uint32_t irq_pin_state;
  62};
  63
  64static void update_irq(struct xlx_pic *p)
  65{
  66    uint32_t i;
  67
  68    /* level triggered interrupt */
  69    if (p->regs[R_MER] & 2) {
  70        p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
  71    }
  72
  73    /* Update the pending register.  */
  74    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
  75
  76    /* Update the vector register.  */
  77    for (i = 0; i < 32; i++) {
  78        if (p->regs[R_IPR] & (1U << i)) {
  79            break;
  80        }
  81    }
  82    if (i == 32)
  83        i = ~0;
  84
  85    p->regs[R_IVR] = i;
  86    qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
  87}
  88
  89static uint64_t
  90pic_read(void *opaque, hwaddr addr, unsigned int size)
  91{
  92    struct xlx_pic *p = opaque;
  93    uint32_t r = 0;
  94
  95    addr >>= 2;
  96    switch (addr)
  97    {
  98        default:
  99            if (addr < ARRAY_SIZE(p->regs))
 100                r = p->regs[addr];
 101            break;
 102
 103    }
 104    D(printf("%s %x=%x\n", __func__, addr * 4, r));
 105    return r;
 106}
 107
 108static void
 109pic_write(void *opaque, hwaddr addr,
 110          uint64_t val64, unsigned int size)
 111{
 112    struct xlx_pic *p = opaque;
 113    uint32_t value = val64;
 114
 115    addr >>= 2;
 116    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
 117    switch (addr) 
 118    {
 119        case R_IAR:
 120            p->regs[R_ISR] &= ~value; /* ACK.  */
 121            break;
 122        case R_SIE:
 123            p->regs[R_IER] |= value;  /* Atomic set ie.  */
 124            break;
 125        case R_CIE:
 126            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
 127            break;
 128        case R_MER:
 129            p->regs[R_MER] = value & 0x3;
 130            break;
 131        case R_ISR:
 132            if ((p->regs[R_MER] & 2)) {
 133                break;
 134            }
 135            /* fallthrough */
 136        default:
 137            if (addr < ARRAY_SIZE(p->regs))
 138                p->regs[addr] = value;
 139            break;
 140    }
 141    update_irq(p);
 142}
 143
 144static const MemoryRegionOps pic_ops = {
 145    .read = pic_read,
 146    .write = pic_write,
 147    .endianness = DEVICE_NATIVE_ENDIAN,
 148    .valid = {
 149        .min_access_size = 4,
 150        .max_access_size = 4
 151    }
 152};
 153
 154static void irq_handler(void *opaque, int irq, int level)
 155{
 156    struct xlx_pic *p = opaque;
 157
 158    /* edge triggered interrupt */
 159    if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
 160        p->regs[R_ISR] |= (level << irq);
 161    }
 162
 163    p->irq_pin_state &= ~(1 << irq);
 164    p->irq_pin_state |= level << irq;
 165    update_irq(p);
 166}
 167
 168static void xilinx_intc_init(Object *obj)
 169{
 170    struct xlx_pic *p = XILINX_INTC(obj);
 171
 172    qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
 173    qdev_init_gpio_out_named(DEVICE(obj), &p->parent_irq, "Outputs", 1);
 174
 175    memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
 176                          R_MAX * 4);
 177    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
 178}
 179
 180static int xilinx_intc_fdt_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
 181                                   uint32_t *cells, int ncells, int max,
 182                                   Error **errp)
 183{
 184    /* FIXME: Add QOM cast macro */
 185    struct xlx_pic *p = (struct xlx_pic *)obj;
 186    uint32_t idx;
 187    uint32_t exp_type;
 188
 189    if (ncells != 2) {
 190        error_setg(errp, "Xilinx Intc requires 2 interrupt cells: %d given",
 191                   ncells);
 192        return 0;
 193    }
 194    idx = cells[0];
 195
 196    if (idx >= 32) {
 197        error_setg(errp, "Xilinx Intc only supports 32 interrupts: index %"
 198                   PRId32 " requested", idx);
 199        return 0;
 200    }
 201
 202    exp_type = p->c_kind_of_intr & (1 << idx) ? 0 : 2;
 203    if (cells[1] != exp_type) {
 204        error_setg(errp, "Xilinx Intc expects interrupt mode %" PRIx32
 205                   " for interrupt %" PRIx32 ", mode %" PRIx32 " given",
 206                   exp_type, idx, cells[1]);
 207        return 0;
 208    }
 209
 210    (*irqs) = qdev_get_gpio_in(DEVICE(obj), idx);
 211    return 1;
 212};
 213
 214static Property xilinx_intc_properties[] = {
 215    DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
 216    DEFINE_PROP_END_OF_LIST(),
 217};
 218
 219static void xilinx_intc_fdt_auto_parent(FDTGenericIntc *obj, Error **errp)
 220{
 221    qdev_connect_gpio_out_named(DEVICE(obj), "Outputs", 0,
 222                                qdev_get_gpio_in(DEVICE(first_cpu), 0));
 223}
 224
 225
 226static void xilinx_intc_class_init(ObjectClass *klass, void *data)
 227{
 228    DeviceClass *dc = DEVICE_CLASS(klass);
 229    FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(klass);
 230
 231    dc->props = xilinx_intc_properties;
 232    fgic->get_irq = xilinx_intc_fdt_get_irq;
 233    fgic->auto_parent = xilinx_intc_fdt_auto_parent;
 234}
 235
 236static const TypeInfo xilinx_intc_info = {
 237    .name          = TYPE_XILINX_INTC,
 238    .parent        = TYPE_SYS_BUS_DEVICE,
 239    .instance_size = sizeof(struct xlx_pic),
 240    .instance_init = xilinx_intc_init,
 241    .class_init    = xilinx_intc_class_init,
 242    .interfaces = (InterfaceInfo[]) {
 243        { TYPE_FDT_GENERIC_INTC },
 244        { }
 245    },
 246};
 247
 248static void xilinx_intc_register_types(void)
 249{
 250    type_register_static(&xilinx_intc_info);
 251}
 252
 253type_init(xilinx_intc_register_types)
 254