qemu/hw/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#include "sysbus.h"
  12
  13#undef DEBUG_PUV3
  14#include "puv3.h"
  15
  16typedef struct {
  17    SysBusDevice busdev;
  18    MemoryRegion iomem;
  19    qemu_irq parent_irq;
  20
  21    uint32_t reg_ICMR;
  22    uint32_t reg_ICPR;
  23} PUV3INTCState;
  24
  25/* Update interrupt status after enabled or pending bits have been changed.  */
  26static void puv3_intc_update(PUV3INTCState *s)
  27{
  28    if (s->reg_ICMR & s->reg_ICPR) {
  29        qemu_irq_raise(s->parent_irq);
  30    } else {
  31        qemu_irq_lower(s->parent_irq);
  32    }
  33}
  34
  35/* Process a change in an external INTC input. */
  36static void puv3_intc_handler(void *opaque, int irq, int level)
  37{
  38    PUV3INTCState *s = opaque;
  39
  40    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
  41    if (level) {
  42        s->reg_ICPR |= (1 << irq);
  43    } else {
  44        s->reg_ICPR &= ~(1 << irq);
  45    }
  46    puv3_intc_update(s);
  47}
  48
  49static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
  50        unsigned size)
  51{
  52    PUV3INTCState *s = opaque;
  53    uint32_t ret = 0;
  54
  55    switch (offset) {
  56    case 0x04: /* INTC_ICMR */
  57        ret = s->reg_ICMR;
  58        break;
  59    case 0x0c: /* INTC_ICIP */
  60        ret = s->reg_ICPR; /* the same value with ICPR */
  61        break;
  62    default:
  63        DPRINTF("Bad offset %x\n", (int)offset);
  64    }
  65    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
  66    return ret;
  67}
  68
  69static void puv3_intc_write(void *opaque, hwaddr offset,
  70        uint64_t value, unsigned size)
  71{
  72    PUV3INTCState *s = opaque;
  73
  74    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
  75    switch (offset) {
  76    case 0x00: /* INTC_ICLR */
  77    case 0x14: /* INTC_ICCR */
  78        break;
  79    case 0x04: /* INTC_ICMR */
  80        s->reg_ICMR = value;
  81        break;
  82    default:
  83        DPRINTF("Bad offset 0x%x\n", (int)offset);
  84        return;
  85    }
  86    puv3_intc_update(s);
  87}
  88
  89static const MemoryRegionOps puv3_intc_ops = {
  90    .read = puv3_intc_read,
  91    .write = puv3_intc_write,
  92    .impl = {
  93        .min_access_size = 4,
  94        .max_access_size = 4,
  95    },
  96    .endianness = DEVICE_NATIVE_ENDIAN,
  97};
  98
  99static int puv3_intc_init(SysBusDevice *dev)
 100{
 101    PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
 102
 103    qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
 104    sysbus_init_irq(&s->busdev, &s->parent_irq);
 105
 106    s->reg_ICMR = 0;
 107    s->reg_ICPR = 0;
 108
 109    memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
 110            PUV3_REGS_OFFSET);
 111    sysbus_init_mmio(dev, &s->iomem);
 112
 113    return 0;
 114}
 115
 116static void puv3_intc_class_init(ObjectClass *klass, void *data)
 117{
 118    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 119
 120    sdc->init = puv3_intc_init;
 121}
 122
 123static const TypeInfo puv3_intc_info = {
 124    .name = "puv3_intc",
 125    .parent = TYPE_SYS_BUS_DEVICE,
 126    .instance_size = sizeof(PUV3INTCState),
 127    .class_init = puv3_intc_class_init,
 128};
 129
 130static void puv3_intc_register_type(void)
 131{
 132    type_register_static(&puv3_intc_info);
 133}
 134
 135type_init(puv3_intc_register_type)
 136