From 5e0ba1a39e6fd114a5557a674c6834d6dc1cca08 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 26 Apr 2011 05:46:02 +0000 Subject: [PATCH] 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 --- sim/bfin/ChangeLog | 12 ++++++++++++ sim/bfin/dv-bfin_gpio.c | 49 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/sim/bfin/ChangeLog b/sim/bfin/ChangeLog index 25944fd..a7e80b1 100644 --- a/sim/bfin/ChangeLog +++ b/sim/bfin/ChangeLog @@ -1,3 +1,15 @@ +2011-04-26 Mike Frysinger + + * 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 * bfin-sim.c (decode_dsp32alu_0): Call STORE instead of SET_DREG for 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 -- 2.7.4