diff options
author | Mike Frysinger <vapier@gentoo.org> | 2011-04-26 05:46:02 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2011-04-26 05:46:02 +0000 |
commit | 5e0ba1a39e6fd114a5557a674c6834d6dc1cca08 (patch) | |
tree | 3fdd1ba35c7d6ef843f7ce63eff3f1bebfd4de65 /sim/bfin/dv-bfin_gpio.c | |
parent | a9c5be0fb781178f8c68a9418c2a90c23f2f3f25 (diff) | |
download | gdb-5e0ba1a39e6fd114a5557a674c6834d6dc1cca08.zip gdb-5e0ba1a39e6fd114a5557a674c6834d6dc1cca08.tar.gz gdb-5e0ba1a39e6fd114a5557a674c6834d6dc1cca08.tar.bz2 |
sim: gpio: update mask a/b signals better
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>
Diffstat (limited to 'sim/bfin/dv-bfin_gpio.c')
-rw-r--r-- | sim/bfin/dv-bfin_gpio.c | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/sim/bfin/dv-bfin_gpio.c b/sim/bfin/dv-bfin_gpio.c index 23d2610..7a6acb6 100644 --- a/sim/bfin/dv-bfin_gpio.c +++ b/sim/bfin/dv-bfin_gpio.c @@ -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 |