qemu/hw/intc/puv3_intc.c
<<
>>
Prefs
   1/*
   2 * INTC device simulation in PKUnity SoC
   3 *
   4 * Copyright (C) 2010-2012 Guan Xuetao
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation, or any later version.
   9 * See the COPYING file in the top-level directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "hw/irq.h"
  14#include "hw/sysbus.h"
  15#include "qom/object.h"
  16
  17#undef DEBUG_PUV3
  18#include "hw/unicore32/puv3.h"
  19#include "qemu/module.h"
  20#include "qemu/log.h"
  21
  22#define TYPE_PUV3_INTC "puv3_intc"
  23OBJECT_DECLARE_SIMPLE_TYPE(PUV3INTCState, PUV3_INTC)
  24
  25struct PUV3INTCState {
  26    SysBusDevice parent_obj;
  27
  28    MemoryRegion iomem;
  29    qemu_irq parent_irq;
  30
  31    uint32_t reg_ICMR;
  32    uint32_t reg_ICPR;
  33};
  34
  35/* Update interrupt status after enabled or pending bits have been changed.  */
  36static void puv3_intc_update(PUV3INTCState *s)
  37{
  38    if (s->reg_ICMR & s->reg_ICPR) {
  39        qemu_irq_raise(s->parent_irq);
  40    } else {
  41        qemu_irq_lower(s->parent_irq);
  42    }
  43}
  44
  45/* Process a change in an external INTC input. */
  46static void puv3_intc_handler(void *opaque, int irq, int level)
  47{
  48    PUV3INTCState *s = opaque;
  49
  50    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
  51    if (level) {
  52        s->reg_ICPR |= (1 << irq);
  53    } else {
  54        s->reg_ICPR &= ~(1 << irq);
  55    }
  56    puv3_intc_update(s);
  57}
  58
  59static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
  60        unsigned size)
  61{
  62    PUV3INTCState *s = opaque;
  63    uint32_t ret = 0;
  64
  65    switch (offset) {
  66    case 0x04: /* INTC_ICMR */
  67        ret = s->reg_ICMR;
  68        break;
  69    case 0x0c: /* INTC_ICIP */
  70        ret = s->reg_ICPR; /* the same value with ICPR */
  71        break;
  72    default:
  73        qemu_log_mask(LOG_GUEST_ERROR,
  74                      "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
  75                      __func__, offset);
  76    }
  77    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
  78    return ret;
  79}
  80
  81static void puv3_intc_write(void *opaque, hwaddr offset,
  82        uint64_t value, unsigned size)
  83{
  84    PUV3INTCState *s = opaque;
  85
  86    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
  87    switch (offset) {
  88    case 0x00: /* INTC_ICLR */
  89    case 0x14: /* INTC_ICCR */
  90        break;
  91    case 0x04: /* INTC_ICMR */
  92        s->reg_ICMR = value;
  93        break;
  94    default:
  95        qemu_log_mask(LOG_GUEST_ERROR,
  96                      "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
  97                      __func__, offset);
  98        return;
  99    }
 100    puv3_intc_update(s);
 101}
 102
 103static const MemoryRegionOps puv3_intc_ops = {
 104    .read = puv3_intc_read,
 105    .write = puv3_intc_write,
 106    .impl = {
 107        .min_access_size = 4,
 108        .max_access_size = 4,
 109    },
 110    .endianness = DEVICE_NATIVE_ENDIAN,
 111};
 112
 113static void puv3_intc_realize(DeviceState *dev, Error **errp)
 114{
 115    PUV3INTCState *s = PUV3_INTC(dev);
 116    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 117
 118    qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR);
 119    sysbus_init_irq(sbd, &s->parent_irq);
 120
 121    s->reg_ICMR = 0;
 122    s->reg_ICPR = 0;
 123
 124    memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc",
 125                          PUV3_REGS_OFFSET);
 126    sysbus_init_mmio(sbd, &s->iomem);
 127}
 128
 129static void puv3_intc_class_init(ObjectClass *klass, void *data)
 130{
 131    DeviceClass *dc = DEVICE_CLASS(klass);
 132    dc->realize = puv3_intc_realize;
 133}
 134
 135static const TypeInfo puv3_intc_info = {
 136    .name = TYPE_PUV3_INTC,
 137    .parent = TYPE_SYS_BUS_DEVICE,
 138    .instance_size = sizeof(PUV3INTCState),
 139    .class_init = puv3_intc_class_init,
 140};
 141
 142static void puv3_intc_register_type(void)
 143{
 144    type_register_static(&puv3_intc_info);
 145}
 146
 147type_init(puv3_intc_register_type)
 148