X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fadi_v5_swd.c;h=eb181cb653a0862304c44829bef9a46d763e4b66;hp=f8d3650edb6894e42795f90f666a4e4384ece0f4;hb=7a80a74e8117332d6fd780f5c4697fe4bd3c41f7;hpb=12e9f6292b391d475214704843504c5817bf783e diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index f8d3650edb..eb181cb653 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * along with this program. If not, see . ***************************************************************************/ /** @@ -55,139 +53,218 @@ #include -/* YUK! - but this is currently a global.... */ -extern struct jtag_interface *jtag_interface; static bool do_sync; static void swd_finish_read(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); if (dap->last_read != NULL) { - swd->read_reg(dap, swd_cmd(true, false, DP_RDBUFF), dap->last_read); + swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read, 0); dap->last_read = NULL; } } static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data); +static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data); static void swd_clear_sticky_errors(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); - swd->write_reg(dap, swd_cmd(false, false, DP_ABORT), - STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); + swd->write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); } static int swd_run_inner(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + int retval; - int retval = swd->run(dap); + retval = swd->run(); if (retval != ERROR_OK) { /* fault response */ - swd_clear_sticky_errors(dap); + dap->do_reconnect = true; } return retval; } +static int swd_connect(struct adiv5_dap *dap) +{ + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + uint32_t dpidr; + int status; + + /* FIXME validate transport config ... is the + * configured DAP present (check IDCODE)? + * Is *only* one DAP configured? + * + * MUST READ DPIDR + */ + + /* Check if we should reset srst already when connecting, but not if reconnecting. */ + if (!dap->do_reconnect) { + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + swd_add_reset(1); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } + } + + /* Note, debugport_init() does setup too */ + swd->switch_seq(JTAG_TO_SWD); + + /* Clear link state, including the SELECT cache. */ + dap->do_reconnect = false; + dap_invalidate_cache(dap); + + swd_queue_dp_read(dap, DP_DPIDR, &dpidr); + + /* force clear all sticky faults */ + swd_clear_sticky_errors(dap); + + status = swd_run_inner(dap); + + if (status == ERROR_OK) { + LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr); + dap->do_reconnect = false; + status = dap_dp_init(dap); + } else + dap->do_reconnect = true; + + return status; +} + static inline int check_sync(struct adiv5_dap *dap) { return do_sync ? swd_run_inner(dap) : ERROR_OK; } +static int swd_check_reconnect(struct adiv5_dap *dap) +{ + if (dap->do_reconnect) + return swd_connect(dap); + + return ERROR_OK; +} + static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); - swd->write_reg(dap, swd_cmd(false, false, DP_ABORT), - DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); + swd->write_reg(swd_cmd(false, false, DP_ABORT), + DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); return check_sync(dap); } /** Select the DP register bank matching bits 7:4 of reg. */ static void swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) { - uint32_t select_dp_bank = (reg & 0x000000F0) >> 4; - - if (reg == DP_SELECT) + /* Only register address 4 is banked. */ + if ((reg & 0xf) != 4) return; - if (select_dp_bank == dap->dp_bank_value) + uint32_t select_dp_bank = (reg & 0x000000F0) >> 4; + uint32_t sel = select_dp_bank + | (dap->select & (DP_SELECT_APSEL | DP_SELECT_APBANK)); + + if (sel == dap->select) return; - dap->dp_bank_value = select_dp_bank; - select_dp_bank |= dap->ap_current | dap->ap_bank_value; + dap->select = sel; - swd_queue_dp_write(dap, DP_SELECT, select_dp_bank); + swd_queue_dp_write(dap, DP_SELECT, sel); } static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); + int retval = swd_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + swd_queue_dp_bankselect(dap, reg); - swd->read_reg(dap, swd_cmd(true, false, reg), data); + swd->read_reg(swd_cmd(true, false, reg), data, 0); return check_sync(dap); } - static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); + int retval = swd_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + swd_finish_read(dap); swd_queue_dp_bankselect(dap, reg); - swd->write_reg(dap, swd_cmd(false, false, reg), data); + swd->write_reg(swd_cmd(false, false, reg), data, 0); return check_sync(dap); } /** Select the AP register bank matching bits 7:4 of reg. */ -static void swd_queue_ap_bankselect(struct adiv5_dap *dap, unsigned reg) +static void swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) { - uint32_t select_ap_bank = reg & 0x000000F0; + struct adiv5_dap *dap = ap->dap; + uint32_t sel = ((uint32_t)ap->ap_num << 24) + | (reg & 0x000000F0) + | (dap->select & DP_SELECT_DPBANK); - if (select_ap_bank == dap->ap_bank_value) + if (sel == dap->select) return; - dap->ap_bank_value = select_ap_bank; - select_ap_bank |= dap->ap_current | dap->dp_bank_value; + dap->select = sel; - swd_queue_dp_write(dap, DP_SELECT, select_ap_bank); + swd_queue_dp_write(dap, DP_SELECT, sel); } -static int swd_queue_ap_read(struct adiv5_dap *dap, unsigned reg, +static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = jtag_interface->swd; + struct adiv5_dap *dap = ap->dap; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); - swd_queue_ap_bankselect(dap, reg); - swd->read_reg(dap, swd_cmd(true, true, reg), dap->last_read); + int retval = swd_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + swd_queue_ap_bankselect(ap, reg); + swd->read_reg(swd_cmd(true, true, reg), dap->last_read, ap->memaccess_tck); dap->last_read = data; return check_sync(dap); } -static int swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg, +static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - const struct swd_driver *swd = jtag_interface->swd; + struct adiv5_dap *dap = ap->dap; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); + int retval = swd_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + swd_finish_read(dap); - swd_queue_ap_bankselect(dap, reg); - swd->write_reg(dap, swd_cmd(false, true, reg), data); + swd_queue_ap_bankselect(ap, reg); + swd->write_reg(swd_cmd(false, true, reg), data, ap->memaccess_tck); return check_sync(dap); } @@ -199,132 +276,27 @@ static int swd_run(struct adiv5_dap *dap) return swd_run_inner(dap); } -const struct dap_ops swd_dap_ops = { - .is_swd = true, +/** Put the SWJ-DP back to JTAG mode */ +static void swd_quit(struct adiv5_dap *dap) +{ + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + + swd->switch_seq(SWD_TO_JTAG); + /* flush the queue before exit */ + swd->run(); +} +const struct dap_ops swd_dap_ops = { + .connect = swd_connect, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, .queue_ap_write = swd_queue_ap_write, .queue_ap_abort = swd_queue_ap_abort, .run = swd_run, + .quit = swd_quit, }; -/* - * This represents the bits which must be sent out on TMS/SWDIO to - * switch a DAP implemented using an SWJ-DP module into SWD mode. - * These bits are stored (and transmitted) LSB-first. - * - * See the DAP-Lite specification, section 2.2.5 for information - * about making the debug link select SWD or JTAG. (Similar info - * is in a few other ARM documents.) - */ -static const uint8_t jtag2swd_bitseq[] = { - /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, - * putting both JTAG and SWD logic into reset state. - */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* Switching sequence enables SWD and disables JTAG - * NOTE: bits in the DP's IDCODE may expose the need for - * an old/obsolete/deprecated sequence (0xb6 0xed). - */ - 0x9e, 0xe7, - /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, - * putting both JTAG and SWD logic into reset state. - */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -/** - * Put the debug link into SWD mode, if the target supports it. - * The link's initial mode may be either JTAG (for example, - * with SWJ-DP after reset) or SWD. - * - * @param target Enters SWD mode (if possible). - * - * Note that targets using the JTAG-DP do not support SWD, and that - * some targets which could otherwise support it may have have been - * configured to disable SWD signaling - * - * @return ERROR_OK or else a fault code. - */ -int dap_to_swd(struct target *target) -{ - struct arm *arm = target_to_arm(target); - int retval; - - LOG_DEBUG("Enter SWD mode"); - - /* REVISIT it's ugly to need to make calls to a "jtag" - * subsystem if the link may not be in JTAG mode... - */ - - retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq), - jtag2swd_bitseq, TAP_INVALID); - if (retval == ERROR_OK) - retval = jtag_execute_queue(); - - /* set up the DAP's ops vector for SWD mode. */ - arm->dap->ops = &swd_dap_ops; - - return retval; -} - -COMMAND_HANDLER(handle_swd_wcr) -{ - int retval; - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - uint32_t wcr; - unsigned trn, scale = 0; - - switch (CMD_ARGC) { - /* no-args: just dump state */ - case 0: - /*retval = swd_queue_dp_read(dap, DP_WCR, &wcr); */ - retval = dap_queue_dp_read(dap, DP_WCR, &wcr); - if (retval == ERROR_OK) - dap->ops->run(dap); - if (retval != ERROR_OK) { - LOG_ERROR("can't read WCR?"); - return retval; - } - - command_print(CMD_CTX, - "turnaround=%" PRIu32 ", prescale=%" PRIu32, - WCR_TO_TRN(wcr), - WCR_TO_PRESCALE(wcr)); - return ERROR_OK; - - case 2: /* TRN and prescale */ - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], scale); - if (scale > 7) { - LOG_ERROR("prescale %d is too big", scale); - return ERROR_FAIL; - } - /* FALL THROUGH */ - - case 1: /* TRN only */ - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], trn); - if (trn < 1 || trn > 4) { - LOG_ERROR("turnaround %d is invalid", trn); - return ERROR_FAIL; - } - - wcr = ((trn - 1) << 8) | scale; - /* FIXME - * write WCR ... - * then, re-init adapter with new TRN - */ - LOG_ERROR("can't yet modify WCR"); - return ERROR_FAIL; - - default: /* too many arguments */ - return ERROR_COMMAND_SYNTAX_ERROR; - } -} - static const struct command_registration swd_commands[] = { { /* @@ -339,15 +311,6 @@ static const struct command_registration swd_commands[] = { .mode = COMMAND_CONFIG, .help = "declare a new SWD DAP" }, - { - .name = "wcr", - .handler = handle_swd_wcr, - .mode = COMMAND_ANY, - .help = "display or update DAP's WCR register", - .usage = "turnaround (1..4), prescale (0..7)", - }, - - /* REVISIT -- add a command for SWV trace on/off */ COMMAND_REGISTRATION_DONE }; @@ -363,15 +326,15 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { + /* FIXME: only place where global 'jtag_interface' is still needed */ + extern struct jtag_interface *jtag_interface; + const struct swd_driver *swd = jtag_interface->swd; int retval; retval = register_commands(ctx, NULL, swd_handlers); - if (retval != ERROR_OK) return retval; - const struct swd_driver *swd = jtag_interface->swd; - /* be sure driver is in SWD mode; start * with hardware default TRN (1), it can be changed later */ @@ -386,50 +349,14 @@ static int swd_select(struct command_context *ctx) return retval; } - /* force DAP into SWD mode (not JTAG) */ - /*retval = dap_to_swd(target);*/ - - if (ctx->current_target) { - /* force DAP into SWD mode (not JTAG) */ - struct target *target = get_current_target(ctx); - retval = dap_to_swd(target); - } - return retval; } static int swd_init(struct command_context *ctx) { - struct target *target = get_current_target(ctx); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - uint32_t idcode; - int status; - - /* Force the DAP's ops vector for SWD mode. - * messy - is there a better way? */ - arm->dap->ops = &swd_dap_ops; - - /* FIXME validate transport config ... is the - * configured DAP present (check IDCODE)? - * Is *only* one DAP configured? - * - * MUST READ IDCODE - */ - - /* Note, debugport_init() does setup too */ - - swd_queue_dp_read(dap, DP_IDCODE, &idcode); - - /* force clear all sticky faults */ - swd_clear_sticky_errors(dap); - - status = swd_run(dap); - - if (status == ERROR_OK) - LOG_INFO("SWD IDCODE %#8.8" PRIx32, idcode); - - return status; + /* nothing done here, SWD is initialized + * together with the DAP */ + return ERROR_OK; } static struct transport swd_transport = {