This is an automated email from Gerrit. Jean-Christian de Rivaz ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2436
-- gerrit commit c6d3440f060ebe9cf633420048567a8a057d4622 Author: Jean-Christian de Rivaz <[email protected]> Date: Thu Dec 11 17:41:03 2014 +0100 Add SWD protocol support to bitbang This is based on the initial work by Paul Fertser with addition of the switch sequences and new ACK handling. In case of WAIT response, the sticky bits are cleared and the last operation is repeated. The ACK handling is based on the interpretation of the 8 February 2006 ARM Debug Interface v5 Architecture Specification Change-Id: I45973dfb4c5d97f3c95826e36c5daac00851f2c2 Signed-off-by: Jean-Christian de Rivaz <[email protected]> diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index 795764a..c403f5d 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -29,6 +29,9 @@ #include <jtag/interface.h> #include <jtag/commands.h> +/* YUK! - but this is currently a global.... */ +extern struct jtag_interface *jtag_interface; + /** * Function bitbang_stableclocks * issues a number of clock cycles while staying in a stable state. @@ -337,3 +340,207 @@ int bitbang_execute_queue(void) return retval; } + + +bool swd_mode; +static int queued_retval; + +static int bitbang_swd_init(void) +{ + LOG_DEBUG("bitbang_swd_init"); + swd_mode = true; + return ERROR_OK; +} + +static void bitbang_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt) +{ + LOG_DEBUG("bitbang_exchange"); + int tdi; + + for (unsigned int i = offset; i < bit_cnt + offset; i++) { + int bytec = i/8; + int bcval = 1 << (i % 8); + tdi = !rnw && (buf[bytec] & bcval); + + bitbang_interface->write(0, 0, tdi); + + if (rnw && buf) { + if (bitbang_interface->swdio_read()) + buf[bytec] |= bcval; + else + buf[bytec] &= ~bcval; + } + + bitbang_interface->write(1, 0, tdi); + } +} + +int bitbang_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + LOG_DEBUG("bitbang_swd_switch_seq"); + + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + bitbang_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len); + break; + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + bitbang_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len); + break; + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + bitbang_exchange(false, (uint8_t *)swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len); + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +void bitbang_switch_to_swd(void) +{ + LOG_DEBUG("bitbang_switch_to_swd"); + bitbang_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len); +} + +static void swd_clear_sticky_errors(struct adiv5_dap *dap) +{ + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + swd->write_reg(dap, swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); +} + +static void bitbang_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value) +{ + LOG_DEBUG("bitbang_swd_read_reg"); + assert(cmd & SWD_CMD_RnW); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skip bitbang_swd_read_reg because queued_retval=%d", queued_retval); + return; + } + + for (;;) { + uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; + + cmd |= SWD_CMD_START | (1 << 7); + bitbang_exchange(false, &cmd, 0, 8); + + bitbang_interface->swdio_drive(false); + bitbang_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 32 + 1 + 1); + bitbang_interface->swdio_drive(true); + + int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3); + uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32); + int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1); + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + data); + + if (ack == SWD_ACK_WAIT) { + LOG_DEBUG("SWD_ACK_WAIT"); + swd_clear_sticky_errors(dap); + continue; + } + + if (ack != SWD_ACK_OK) { + LOG_DEBUG("No acknowledge detected"); + queued_retval = ack; + return; + } + + if (parity != parity_u32(data)) { + LOG_DEBUG("Wrong parity detected"); + queued_retval = ERROR_FAIL; + return; + } + + if (value) + *value = data; + break; + } + + if (cmd & SWD_CMD_APnDP) + bitbang_exchange(true, NULL, 0, dap->memaccess_tck); +} + +static void bitbang_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value) +{ + LOG_DEBUG("bitbang_swd_write_reg"); + assert(!(cmd & SWD_CMD_RnW)); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skip bitbang_swd_write_reg because queued_retval=%d", queued_retval); + return; + } + + for (;;) { + uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; + buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value); + buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value)); + + cmd |= SWD_CMD_START | (1 << 7); + bitbang_exchange(false, &cmd, 0, 8); + + bitbang_interface->swdio_drive(false); + bitbang_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 1); + bitbang_interface->swdio_drive(true); + + int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3); + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); + + if (ack == SWD_ACK_WAIT) { + bitbang_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1); + LOG_DEBUG("SWD_ACK_WAIT"); + swd_clear_sticky_errors(dap); + continue; + } + + if (ack != SWD_ACK_OK) { + LOG_DEBUG("No acknowledge detected"); + queued_retval = ack; + return; + } + + bitbang_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1); + break; + } + + if (cmd & SWD_CMD_APnDP) + bitbang_exchange(true, NULL, 0, dap->memaccess_tck); +} + +static int bitbang_swd_run_queue(struct adiv5_dap *dap) +{ + LOG_DEBUG("bitbang_swd_run_queue"); + /* A transaction must be followed by another transaction or at least 8 idle cycles to + * ensure that data is clocked through the AP. */ + bitbang_exchange(true, NULL, 0, 8); + + int retval = queued_retval; + queued_retval = ERROR_OK; + LOG_DEBUG("SWD queue return value: %02x", retval); + return retval; +} + +const struct swd_driver bitbang_swd = { + .init = bitbang_swd_init, + .switch_seq = bitbang_swd_switch_seq, + .read_reg = bitbang_swd_read_reg, + .write_reg = bitbang_swd_write_reg, + .run = bitbang_swd_run_queue, +}; diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index 6b7d63a..52e113d 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -24,6 +24,8 @@ #ifndef BITBANG_H #define BITBANG_H +#include <jtag/swd.h> + struct bitbang_interface { /* low level callbacks (for bitbang) */ @@ -31,10 +33,18 @@ struct bitbang_interface { void (*write)(int tck, int tms, int tdi); void (*reset)(int trst, int srst); void (*blink)(int on); + int (*swdio_read)(void); + void (*swdio_drive)(bool on); }; +const struct swd_driver bitbang_swd; + +extern bool swd_mode; + int bitbang_execute_queue(void); extern struct bitbang_interface *bitbang_interface; +void bitbang_switch_to_swd(void); +int bitbang_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq); #endif /* BITBANG_H */ -- ------------------------------------------------------------------------------ Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server from Actuate! Instantly Supercharge Your Business Reports and Dashboards with Interactivity, Sharing, Native Excel Exports, App Integration & more Get technology previously reserved for billion-dollar corporations, FREE http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
