summary refs log tree commit diff stats
path: root/hw/gpio/pl061.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-09-12 15:12:26 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-09-12 15:12:26 +0100
commit4c24f4004089a308c5de8ed720cf6bd1746aedd8 (patch)
treed83f318edd5b987a94d0a16ed8a25a215c645fca /hw/gpio/pl061.c
parent6cd14054b67774cc58a51fca6660cfa1d3c08059 (diff)
parent92df845070290236d1b28b03453deec1ae9c4263 (diff)
downloadfocaccia-qemu-4c24f4004089a308c5de8ed720cf6bd1746aedd8.tar.gz
focaccia-qemu-4c24f4004089a308c5de8ed720cf6bd1746aedd8.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140912' into staging
target-arm:
 * add "linux,stdout-path" to the virt DTB
 * fix a long standing bug with IRQ disabling on Cortex-M CPUs
 * implement input interrupt logic in the PL061
 * fix failure to load correct SP/PC on reset of Cortex-M CPUs
   if the vector table is not in a ROM-blob-in-RAM
 * provide flash devices for boot ROMs in the virt board
 * implement architectural watchpoints
 * fix misimplementation of Inner Shareable TLB operations that
   caused instability of guests in TCG SMP configurations
 * configure PL011 and PL031 in the virt board correctly with
   level-triggered interrupts rather than edge-triggered
 * support providing a device tree blob to ROM (firmware)
   images as well as to kernels

# gpg: Signature made Fri 12 Sep 2014 14:19:08 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20140912: (23 commits)
  hw/arm/boot: enable DTB support when booting ELF images
  hw/arm/boot: load device tree to base of DRAM if no -kernel option was passed
  hw/arm/boot: pass an address limit to and return size from load_dtb()
  hw/arm/boot: load DTB as a ROM image
  hw/arm/virt: fix pl011 and pl031 irq flags
  target-arm: Make *IS TLB maintenance ops affect all CPUs
  target-arm: Push legacy wildcard TLB ops back into v6
  target-arm: Implement minimal DBGVCR, OSDLR_EL1, MDCCSR_EL0
  target-arm: Remove comment about MDSCR_EL1 being dummy implementation
  target-arm: Set DBGDSCR.MOE for debug exceptions taken to AArch32
  target-arm: Implement handling of fired watchpoints
  target-arm: Move extended_addresses_enabled() to internals.h
  target-arm: Implement setting of watchpoints
  cpu-exec: Make debug_excp_handler a QOM CPU method
  exec.c: Record watchpoint fault address and direction
  exec.c: Provide full set of dummy wp remove functions in user-mode
  exec.c: Relax restrictions on watchpoint length and alignment
  hw/arm/virt: Provide flash devices for boot ROMs
  target-arm: Fix broken indentation in arm_cpu_reest()
  target-arm: Fix resetting issues on ARMv7-M CPUs
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/gpio/pl061.c')
-rw-r--r--hw/gpio/pl061.c59
1 files changed, 45 insertions, 14 deletions
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index dd4ea293e2..bd03e99975 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -37,7 +37,8 @@ typedef struct PL061State {
     MemoryRegion iomem;
     uint32_t locked;
     uint32_t data;
-    uint32_t old_data;
+    uint32_t old_out_data;
+    uint32_t old_in_data;
     uint32_t dir;
     uint32_t isense;
     uint32_t ibe;
@@ -63,12 +64,13 @@ typedef struct PL061State {
 
 static const VMStateDescription vmstate_pl061 = {
     .name = "pl061",
-    .version_id = 2,
-    .minimum_version_id = 1,
+    .version_id = 3,
+    .minimum_version_id = 3,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32(locked, PL061State),
         VMSTATE_UINT32(data, PL061State),
-        VMSTATE_UINT32(old_data, PL061State),
+        VMSTATE_UINT32(old_out_data, PL061State),
+        VMSTATE_UINT32(old_in_data, PL061State),
         VMSTATE_UINT32(dir, PL061State),
         VMSTATE_UINT32(isense, PL061State),
         VMSTATE_UINT32(ibe, PL061State),
@@ -98,23 +100,52 @@ static void pl061_update(PL061State *s)
     uint8_t out;
     int i;
 
+    DPRINTF("dir = %d, data = %d\n", s->dir, s->data);
+
     /* Outputs float high.  */
     /* FIXME: This is board dependent.  */
     out = (s->data & s->dir) | ~s->dir;
-    changed = s->old_data ^ out;
-    if (!changed)
-        return;
+    changed = s->old_out_data ^ out;
+    if (changed) {
+        s->old_out_data = out;
+        for (i = 0; i < 8; i++) {
+            mask = 1 << i;
+            if (changed & mask) {
+                DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
+                qemu_set_irq(s->out[i], (out & mask) != 0);
+            }
+        }
+    }
 
-    s->old_data = out;
-    for (i = 0; i < 8; i++) {
-        mask = 1 << i;
-        if (changed & mask) {
-            DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
-            qemu_set_irq(s->out[i], (out & mask) != 0);
+    /* Inputs */
+    changed = (s->old_in_data ^ s->data) & ~s->dir;
+    if (changed) {
+        s->old_in_data = s->data;
+        for (i = 0; i < 8; i++) {
+            mask = 1 << i;
+            if (changed & mask) {
+                DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0);
+
+                if (!(s->isense & mask)) {
+                    /* Edge interrupt */
+                    if (s->ibe & mask) {
+                        /* Any edge triggers the interrupt */
+                        s->istate |= mask;
+                    } else {
+                        /* Edge is selected by IEV */
+                        s->istate |= ~(s->data ^ s->iev) & mask;
+                    }
+                }
+            }
         }
     }
 
-    /* FIXME: Implement input interrupts.  */
+    /* Level interrupt */
+    s->istate |= ~(s->data ^ s->iev) & s->isense;
+
+    DPRINTF("istate = %02X\n", s->istate);
+
+    qemu_set_irq(s->irq, (s->istate & s->im) != 0);
 }
 
 static uint64_t pl061_read(void *opaque, hwaddr offset,