diff options
author | Fatih Aşıcı <fatih.asici@gmail.com> | 2014-02-14 13:37:04 +0200 |
---|---|---|
committer | Andreas Fritiofson <andreas.fritiofson@gmail.com> | 2014-06-28 09:25:06 +0000 |
commit | 31138437c38348711a1890f9d39f73f4e5e989d5 (patch) | |
tree | 8ae563f96f1c03d247d9cf560a93a951c6d7f935 /src/target/adi_v5_swd.c | |
parent | e3be699f51f11e54f8478e65367b90e3283eaf69 (diff) | |
download | riscv-openocd-31138437c38348711a1890f9d39f73f4e5e989d5.zip riscv-openocd-31138437c38348711a1890f9d39f73f4e5e989d5.tar.gz riscv-openocd-31138437c38348711a1890f9d39f73f4e5e989d5.tar.bz2 |
adi_v5_swd: Improve SWD support
Fix bug in parity calculation macro.
Cache and update the selected DP bank when necessary.
Add aborts when the Ack code signals a failure (we should really only
clear the sticky bits, but this will do for now).
Change-Id: I38a4da136ba1d9e989b33c1875a80c0b1b2be874
Signed-off-by: Fatih Aşıcı <fatih.asici@gmail.com>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1950
Tested-by: jenkins
Diffstat (limited to 'src/target/adi_v5_swd.c')
-rw-r--r-- | src/target/adi_v5_swd.c | 112 |
1 files changed, 101 insertions, 11 deletions
diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 6ff858a..c9c3ae5 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -58,14 +58,56 @@ /* YUK! - but this is currently a global.... */ extern struct jtag_interface *jtag_interface; +static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, + uint32_t data); + +static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + return swd->write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); +} + +/** Select the DP register bank matching bits 7:4 of reg. */ +static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select_dp_bank = (reg & 0x000000F0) >> 4; + + if (reg == DP_SELECT) + return ERROR_OK; + + if (select_dp_bank == dap->dp_bank_value) + return ERROR_OK; + + dap->dp_bank_value = select_dp_bank; + select_dp_bank |= dap->ap_current | dap->ap_bank_value; + + return swd_queue_dp_write(dap, DP_SELECT, select_dp_bank); +} + static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { + int retval; /* REVISIT status return vs ack ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->read_reg(swd_cmd(true, false, reg), data); + retval = swd_queue_dp_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + retval = swd->read_reg(swd_cmd(true, false, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } static int swd_queue_idcode_read(struct adiv5_dap *dap, @@ -82,39 +124,82 @@ static int swd_queue_idcode_read(struct adiv5_dap *dap, static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) { + int retval; /* REVISIT status return vs ack ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->write_reg(swd_cmd(false, false, reg), data); + retval = swd_queue_dp_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + retval = swd->write_reg(swd_cmd(false, false, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } +/** Select the AP register bank matching bits 7:4 of reg. */ +static int swd_queue_ap_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select_ap_bank = reg & 0x000000F0; + + if (select_ap_bank == dap->ap_bank_value) + return ERROR_OK; + + dap->ap_bank_value = select_ap_bank; + select_ap_bank |= dap->ap_current | dap->dp_bank_value; + + return swd_queue_dp_write(dap, DP_SELECT, select_ap_bank); +} static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - /* REVISIT APSEL ... */ /* REVISIT status return ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->read_reg(swd_cmd(true, true, reg), data); + int retval = swd_queue_ap_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + retval = swd->read_reg(swd_cmd(true, true, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - /* REVISIT APSEL ... */ /* REVISIT status return ... */ const struct swd_driver *swd = jtag_interface->swd; assert(swd); - return swd->write_reg(swd_cmd(false, true, reg), data); -} + int retval = swd_queue_ap_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; -static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack) -{ - return ERROR_FAIL; + retval = swd->write_reg(swd_cmd(false, true, reg), data); + + if (retval != ERROR_OK) { + /* fault response */ + uint8_t ack = retval & 0xff; + swd_queue_ap_abort(dap, &ack); + } + + return retval; } /** Executes all queued DAP operations. */ @@ -356,8 +441,13 @@ static int swd_init(struct command_context *ctx) if (status == ERROR_OK) LOG_INFO("SWD IDCODE %#8.8" PRIx32, idcode); - return status; + /* force clear all sticky faults */ + swd_queue_ap_abort(dap, &ack); + + /* this is a workaround to get polling working */ + jtag_add_reset(0, 0); + return status; } static struct transport swd_transport = { |