sim: gpio: update mask a/b signals better
authorMike Frysinger <vapier@gentoo.org>
Tue, 26 Apr 2011 05:46:02 +0000 (05:46 +0000)
committerMike Frysinger <vapier@gentoo.org>
Tue, 26 Apr 2011 05:46:02 +0000 (05:46 +0000)
When the mask a/b MMRs are written, the output signal might change levels
(as pins are [un]masked), so make sure we update the output level.

Further, make sure we handle edge ints correctly by first sending a high
signal followed by a low signal.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
sim/bfin/ChangeLog
sim/bfin/dv-bfin_gpio.c

index 25944fd5d4f268e61173f545aa5b896e70d81578..a7e80b1ad35564d6957f413d98f04fcb79413618 100644 (file)
@@ -1,3 +1,15 @@
+2011-04-26  Mike Frysinger  <vapier@gentoo.org>
+
+       * dv-bfin_gpio.c (bfin_gpio): Add "int_state" member.
+       (bfin_gpio_forward_int, bfin_gpio_forward_ints): New functions.
+       (bfin_gpio_io_write_buffer): Call bfin_gpio_forward_int when the
+       mask a or mask b MMRs are written.
+       (bfin_gpio_port_event): When handling edge gpios, set the bit in
+       int_state, call bfin_gpio_forward_ints, and then clear the bit.
+       When handling level gpios, clear/set the bit in int_state rather
+       than returning immediately.  Call bfin_gpio_forward_ints instead
+       of checking mask[ab] and calling HW_TRACE/hw_port_event directly.
+
 2011-04-16  Mike Frysinger  <vapier@gentoo.org>
 
        * bfin-sim.c (decode_dsp32alu_0): Call STORE instead of SET_DREG for
index 23d2610e6683aaeb8d199663df327626b812f5ea..7a6acb6e1641f57aca40a833957ae53aa1365e92 100644 (file)
@@ -28,6 +28,8 @@ struct bfin_gpio
 {
   bu32 base;
 
+  bu16 int_state;
+
   /* Order after here is important -- matches hardware MMR layout.  */
   bu16 BFIN_MMR_16(data);
   bu16 BFIN_MMR_16(clear);
@@ -60,6 +62,20 @@ static const char * const mmr_names[] =
 };
 #define mmr_name(off) mmr_names[(off) / 4]
 
+static void
+bfin_gpio_forward_int (struct hw *me, struct bfin_gpio *port, bu32 mask,
+                      int dst_port)
+{
+  HW_TRACE ((me, "resending levels on port %c", 'a' + dst_port));
+  hw_port_event (me, dst_port, !!(port->int_state & mask));
+}
+static void
+bfin_gpio_forward_ints (struct hw *me, struct bfin_gpio *port)
+{
+  bfin_gpio_forward_int (me, port, port->maska, 0);
+  bfin_gpio_forward_int (me, port, port->maskb, 1);
+}
+
 static unsigned
 bfin_gpio_io_write_buffer (struct hw *me, const void *source, int space,
                           address_word addr, unsigned nr_bytes)
@@ -115,6 +131,17 @@ bfin_gpio_io_write_buffer (struct hw *me, const void *source, int space,
       break;
     }
 
+  /* If updating masks, make sure we send updated port info.  */
+  switch (mmr_off)
+    {
+    case mmr_offset(maska) ... mmr_offset(maska_toggle):
+      bfin_gpio_forward_int (me, port, port->maska, 0);
+      break;
+    case mmr_offset(maskb) ... mmr_offset(maskb_toggle):
+      bfin_gpio_forward_int (me, port, port->maskb, 1);
+      break;
+    }
+
   return nr_bytes;
 }
 
@@ -250,6 +277,11 @@ bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source,
              return;
            }
        }
+
+      /* Send the signal up, and then fall through to clear it.  */
+      port->int_state |= bit;
+      bfin_gpio_forward_ints (me, port);
+      port->int_state &= ~bit;
     }
   else
     {
@@ -258,21 +290,14 @@ bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source,
        {
          HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i",
                     !!(port->edge & bit), !!(port->polar & bit), nlvl));
-         return;
+         /* We still need to signal SIC to clear the int, so don't return.  */
+         port->int_state &= ~bit;
        }
+      else
+       port->int_state |= bit;
     }
 
-  /* If the masks allow it, push the interrupt even higher.  */
-  if (port->maska & bit)
-    {
-      HW_TRACE ((me, "pin %i triggered an int via mask a", my_port));
-      hw_port_event (me, 0, 1);
-    }
-  if (port->maskb & bit)
-    {
-      HW_TRACE ((me, "pin %i triggered an int via mask b", my_port));
-      hw_port_event (me, 1, 1);
-    }
+  bfin_gpio_forward_ints (me, port);
 }
 
 static void