qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 07/18] hw: add QEMU model for Faraday interrupt cont


From: Dante
Subject: [Qemu-devel] [PATCH 07/18] hw: add QEMU model for Faraday interrupt controller
Date: Fri, 18 Jan 2013 14:29:41 +0800

Signed-off-by: Kuo-Jung Su <address@hidden>
---
 hw/ftintc020.c |  342 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 342 insertions(+)
 create mode 100644 hw/ftintc020.c

diff --git a/hw/ftintc020.c b/hw/ftintc020.c
new file mode 100644
index 0000000..2f78390
--- /dev/null
+++ b/hw/ftintc020.c
@@ -0,0 +1,342 @@
+/*
+ * Faraday FTINTC020 Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ *
+ * Written by Dante Su <address@hidden>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    ARMCPU *cpu;
+    qemu_irq irqs[64];
+    
+    uint32_t irq_pin[2];    /* IRQ pin state */
+    uint32_t fiq_pin[2];    /* IRQ pin state */
+
+    /* HW register caches */
+    uint32_t irq_src[2];    /* IRQ source register */
+    uint32_t irq_ena[2];    /* IRQ enable register */
+    uint32_t irq_mod[2];    /* IRQ mode register */
+    uint32_t irq_lvl[2];    /* IRQ level register */
+    uint32_t fiq_src[2];    /* FIQ source register */
+    uint32_t fiq_ena[2];    /* FIQ enable register */
+    uint32_t fiq_mod[2];    /* FIQ mode register */
+    uint32_t fiq_lvl[2];    /* FIQ level register */
+} ftintc020_state;
+
+qemu_irq *ftintc020_init(hwaddr base, ARMCPU *cpu);
+
+static void ftintc020_update(void *opaque)
+{
+    uint32_t mask[2];
+    ftintc020_state *s = (ftintc020_state *) opaque;
+
+    /* FIQ */
+    mask[0] = s->fiq_src[0] & s->fiq_ena[0];
+    mask[1] = s->fiq_src[1] & s->fiq_ena[1];
+
+    if (mask[0] || mask[1]) {
+        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ);
+    } else {
+        cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ);
+    }
+
+    /* IRQ */
+    mask[0] = s->irq_src[0] & s->irq_ena[0];
+    mask[1] = s->irq_src[1] & s->irq_ena[1];
+
+    if (mask[0] || mask[1]) {
+        cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
+    }
+}
+
+/* Note: Here level means state of the signal on a pin */
+static void ftintc020_set_irq(void *opaque, int irq, int level)
+{
+    ftintc020_state *s = (ftintc020_state *) opaque;
+    uint32_t i = irq / 32;
+    uint32_t mask = 1 << (irq % 32);
+
+    if (s->irq_mod[i] & mask) {
+        /* Edge Triggered */
+        if (s->irq_lvl[i] & mask) {
+            /* Falling Active */
+            if ((s->irq_pin[i] & mask) && !level) {
+                s->irq_src[i] |=  mask;
+                s->fiq_src[i] |=  mask;
+            }
+        } else {
+            /* Rising Active */
+            if (!(s->irq_pin[i] & mask) && level) {
+                s->irq_src[i] |=  mask;
+                s->fiq_src[i] |=  mask;
+            }
+        }
+    } else {
+        /* Level Triggered */
+        if (s->irq_lvl[i] & mask) {
+            /* Low Active */
+            if (level) {
+                s->irq_src[i] &= ~mask;
+                s->fiq_src[i] &= ~mask;
+            } else {
+                s->irq_src[i] |=  mask;
+                s->fiq_src[i] |=  mask;
+            }
+        } else {
+            /* High Active */
+            if (!level) {
+                s->irq_src[i] &= ~mask;
+                s->fiq_src[i] &= ~mask;
+            } else {
+                s->irq_src[i] |=  mask;
+                s->fiq_src[i] |=  mask;
+            }
+        }
+    }
+    
+    /* update IRQ/FIQ pin states */
+    if (level) {
+        s->irq_pin[i] |= mask;
+        s->fiq_pin[i] |= mask;
+    } else {
+        s->irq_pin[i] &= ~mask;
+        s->fiq_pin[i] &= ~mask;
+    }
+
+    ftintc020_update(s);
+}
+
+static uint64_t ftintc020_mem_read(void *opaque, hwaddr offset, unsigned size)
+{
+    ftintc020_state *s = (ftintc020_state *) opaque;
+
+    switch (offset) {
+    /*
+     * IRQ
+     */
+    case 0x0000:    /* IRQ source register */
+        return s->irq_src[0];
+    case 0x0004:    /* IRQ enable register */
+        return s->irq_ena[0];
+    case 0x000C:    /* IRQ trigger-mode register */
+        return s->irq_mod[0];
+    case 0x0010:    /* IRQ trigger-level register */
+        return s->irq_lvl[0];
+    case 0x0014:    /* IRQ status register */
+        return s->irq_src[0] & s->irq_ena[0];
+    case 0x0060:    /* IRQ source register */
+        return s->irq_src[1];
+    case 0x0064:    /* IRQ enable register */
+        return s->irq_ena[1];
+    case 0x006C:    /* IRQ trigger-mode register */
+        return s->irq_mod[1];
+    case 0x0070:    /* IRQ trigger-level register */
+        return s->irq_lvl[1];
+    case 0x0074:    /* IRQ status register */
+        return s->irq_src[1] & s->irq_ena[1];
+
+    /*
+     * FIQ
+     */
+    case 0x0020:    /* FIQ source register */
+        return s->fiq_src[0];
+    case 0x0024:    /* FIQ enable register */
+        return s->fiq_ena[0];
+    case 0x002C:    /* FIQ trigger-mode register */
+        return s->fiq_mod[0];
+    case 0x0030:    /* FIQ trigger-level register */
+        return s->fiq_lvl[0];
+    case 0x0034:    /* FIQ status register */
+        return s->fiq_src[0] & s->fiq_ena[0];
+    case 0x0080:    /* FIQ source register */
+        return s->fiq_src[1];
+    case 0x0084:    /* FIQ enable register */
+        return s->fiq_ena[1];
+    case 0x008C:    /* FIQ trigger-mode register */
+        return s->fiq_mod[1];
+    case 0x0090:    /* FIQ trigger-level register */
+        return s->fiq_lvl[1];
+    case 0x0094:    /* FIQ status register */
+        return s->fiq_src[1] & s->fiq_ena[1];
+
+    default:
+        return 0;
+    }
+}
+
+static void ftintc020_mem_write(void *opaque, hwaddr offset, uint64_t value, 
unsigned size)
+{
+    ftintc020_state *s = (ftintc020_state *) opaque;
+    switch (offset) {
+    /*
+     * IRQ
+     */
+    case 0x0004:    /* IRQ enable register */
+        s->irq_ena[0] = (uint32_t)value;
+        break;
+    case 0x0008:    /* IRQ interrupt clear register */
+        value = ~(value & s->irq_mod[0]);
+        s->irq_src[0] &= (uint32_t)value;
+        break;
+    case 0x000C:
+        s->irq_mod[0] = (uint32_t)value;
+        break;
+    case 0x0010:
+        s->irq_lvl[0] = (uint32_t)value;
+        break;
+    case 0x0064:    /* IRQ enable register */
+        s->irq_ena[1] = (uint32_t)value;
+        break;
+    case 0x0068:    /* IRQ interrupt clear register */
+        value = ~(value & s->irq_mod[1]);
+        s->irq_src[1] &= (uint32_t)value;
+        break;
+    case 0x006C:
+        s->irq_mod[1] = (uint32_t)value;
+        break;
+    case 0x0070:
+        s->irq_lvl[1] = (uint32_t)value;
+        break;
+
+    /*
+     * FIQ
+     */
+    case 0x0024:    /* FIQ enable register */
+        s->fiq_ena[0] = (uint32_t)value;
+        break;
+    case 0x0028:    /* FIQ interrupt clear register */
+        value = ~(value & s->fiq_mod[0]);
+        s->fiq_src[0] &= (uint32_t)value;
+        break;
+    case 0x002C:
+        s->fiq_mod[0] = (uint32_t)value;
+        break;
+    case 0x0030:
+        s->fiq_lvl[0] = (uint32_t)value;
+        break;
+    case 0x0084:    /* FIQ enable register */
+        s->fiq_ena[1] = (uint32_t)value;
+        break;
+    case 0x0088:    /* FIQ interrupt clear register */
+        value = ~(value & s->fiq_mod[1]);
+        s->fiq_src[1] &= (uint32_t)value;
+        break;
+    case 0x008C:
+        s->fiq_mod[1] = (uint32_t)value;
+        break;
+    case 0x0090:
+        s->fiq_lvl[1] = (uint32_t)value;
+        break;
+
+    default:
+        return;
+    }
+
+    ftintc020_update(s);
+}
+
+static const MemoryRegionOps ftintc020_mem_ops = {
+    .read = ftintc020_mem_read,
+    .write = ftintc020_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ftintc020_reset(DeviceState *d)
+{
+    ftintc020_state *s = DO_UPCAST(ftintc020_state, busdev.qdev, d);
+    
+    s->irq_pin[0] = 0;
+    s->irq_pin[1] = 0;
+    s->fiq_pin[0] = 0;
+    s->fiq_pin[1] = 0;
+    
+    s->irq_src[0] = 0;
+    s->irq_src[1] = 0;
+    s->irq_ena[0] = 0;
+    s->irq_ena[1] = 0;
+    s->fiq_src[0] = 0;
+    s->fiq_src[1] = 0;
+    s->fiq_ena[0] = 0;
+    s->fiq_ena[1] = 0;
+
+    ftintc020_update(s);
+}
+
+qemu_irq *ftintc020_init(hwaddr base, ARMCPU *cpu)
+{
+    int i;
+    DeviceState *ds = qdev_create(NULL, "ftintc020");
+    ftintc020_state *s = FROM_SYSBUS(ftintc020_state, sysbus_from_qdev(ds));
+
+    s->cpu = cpu;
+    ftintc020_reset(ds);
+    qdev_init_nofail(ds);
+    qdev_init_gpio_in(ds, ftintc020_set_irq, 64);
+    for (i = 0; i < 64; ++i)
+        s->irqs[i] = qdev_get_gpio_in(ds, i);
+
+    /* Enable IC memory-mapped registers access.  */
+    memory_region_init_io(&s->iomem, &ftintc020_mem_ops, s, "ftintc020", 
0x1000);
+    sysbus_init_mmio(sysbus_from_qdev(ds), &s->iomem);
+    sysbus_mmio_map(sysbus_from_qdev(ds), 0, base);
+
+    return s->irqs;
+}
+
+static VMStateDescription vmstate_ftintc020_regs = {
+    .name = "ftintc020",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(irq_src, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(irq_ena, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(irq_mod, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(irq_lvl, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(fiq_src, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(fiq_ena, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(fiq_mod, ftintc020_state, 2),
+        VMSTATE_UINT32_ARRAY(fiq_lvl, ftintc020_state, 2),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static int ftintc020_initfn(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static void ftintc020_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    sdc->init  = ftintc020_initfn;
+    k->vmsd    = &vmstate_ftintc020_regs;
+    k->reset   = ftintc020_reset;
+    k->no_user = 1;
+}
+
+static TypeInfo ftintc020_info = {
+    .name          = "ftintc020",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ftintc020_state),
+    .class_init    = ftintc020_class_init,
+};
+
+static void ftintc020_register_types(void)
+{
+    type_register_static(&ftintc020_info);
+}
+
+type_init(ftintc020_register_types)
-- 
1.7.9.5


********************* Confidentiality Notice ************************
This electronic message and any attachments may contain
confidential and legally privileged information or
information which is otherwise protected from disclosure.
If you are not the intended recipient,please do not disclose
the contents, either in whole or in part, to anyone,and
immediately delete the message and any attachments from
your computer system and destroy all hard copies.
Thank you for your cooperation.
***********************************************************************




reply via email to

[Prev in Thread] Current Thread [Next in Thread]