X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fadi_v5_swd.c;h=f8d3650edb6894e42795f90f666a4e4384ece0f4;hp=5a3570d536f457734f084fcbb0e408ef78c9afa0;hb=12e9f6292b391d475214704843504c5817bf783e;hpb=c8b57198025c414f8d19577e6846021843c2a751 diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 5a3570d536..f8d3650edb 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -15,7 +15,7 @@ * 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., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ***************************************************************************/ /** @@ -55,70 +55,153 @@ #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; + if (dap->last_read != NULL) { + swd->read_reg(dap, swd_cmd(true, false, DP_RDBUFF), dap->last_read); + dap->last_read = NULL; + } +} -static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, - uint32_t *data) +static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data); + +static void swd_clear_sticky_errors(struct adiv5_dap *dap) { - // REVISIT status return vs ack ... - return swd->read_reg(swd_cmd(true, false, reg), data); + 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 int swd_queue_idcode_read(struct adiv5_dap *dap, - uint8_t *ack, uint32_t *data) +static int swd_run_inner(struct adiv5_dap *dap) { - int status = swd_queue_dp_read(dap, DP_IDCODE, data); - if (status < 0) - return status; - *ack = status; - // ?? - return ERROR_OK; + const struct swd_driver *swd = jtag_interface->swd; + + int retval = swd->run(dap); + + if (retval != ERROR_OK) { + /* fault response */ + swd_clear_sticky_errors(dap); + } + + return retval; } -static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, - uint32_t data) +static inline int check_sync(struct adiv5_dap *dap) { - // REVISIT status return vs ack ... - return swd->write_reg(swd_cmd(false, false, reg), data); + return do_sync ? swd_run_inner(dap) : ERROR_OK; } +static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + swd->write_reg(dap, swd_cmd(false, false, DP_ABORT), + DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); + 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) + return; + + if (select_dp_bank == dap->dp_bank_value) + return; + + dap->dp_bank_value = select_dp_bank; + select_dp_bank |= dap->ap_current | dap->ap_bank_value; -static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, + 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) { - // REVISIT APSEL ... - // REVISIT status return ... - return swd->read_reg(swd_cmd(true, true, reg), data); + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + swd_queue_dp_bankselect(dap, reg); + swd->read_reg(dap, swd_cmd(true, false, reg), data); + + return check_sync(dap); } -static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, + +static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - // REVISIT APSEL ... - // REVISIT status return ... - return swd->write_reg(swd_cmd(false, true, reg), data); + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + swd_finish_read(dap); + swd_queue_dp_bankselect(dap, reg); + swd->write_reg(dap, swd_cmd(false, false, reg), data); + + return check_sync(dap); } -static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack) +/** Select the AP register bank matching bits 7:4 of reg. */ +static void swd_queue_ap_bankselect(struct adiv5_dap *dap, unsigned reg) { - return ERROR_FAIL; + uint32_t select_ap_bank = reg & 0x000000F0; + + if (select_ap_bank == dap->ap_bank_value) + return; + + dap->ap_bank_value = select_ap_bank; + select_ap_bank |= dap->ap_current | dap->dp_bank_value; + + 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) +{ + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + swd_queue_ap_bankselect(dap, reg); + swd->read_reg(dap, swd_cmd(true, true, reg), dap->last_read); + dap->last_read = data; + + return check_sync(dap); +} + +static int swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + const struct swd_driver *swd = jtag_interface->swd; + assert(swd); + + swd_finish_read(dap); + swd_queue_ap_bankselect(dap, reg); + swd->write_reg(dap, swd_cmd(false, true, reg), data); + + return check_sync(dap); } /** Executes all queued DAP operations. */ static int swd_run(struct adiv5_dap *dap) { - /* for now the SWD interface hard-wires a zero-size queue. */ - - /* FIXME but we still need to check and scrub - * any hardware errors ... - */ - return ERROR_OK; + swd_finish_read(dap); + return swd_run_inner(dap); } const struct dap_ops swd_dap_ops = { .is_swd = true, - .queue_idcode_read = swd_queue_idcode_read, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, @@ -187,22 +270,19 @@ int dap_to_swd(struct target *target) 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; + 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 = 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); @@ -212,7 +292,7 @@ struct adiv5_dap *dap = arm->dap; } command_print(CMD_CTX, - "turnaround=%d, prescale=%d", + "turnaround=%" PRIu32 ", prescale=%" PRIu32, WCR_TO_TRN(wcr), WCR_TO_PRESCALE(wcr)); return ERROR_OK; @@ -283,7 +363,6 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { - struct target *target = get_current_target(ctx); int retval; retval = register_commands(ctx, NULL, swd_handlers); @@ -291,6 +370,8 @@ static int swd_select(struct command_context *ctx) 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 */ @@ -299,14 +380,20 @@ static int swd_select(struct command_context *ctx) return ERROR_FAIL; } - retval = swd->init(1); + retval = swd->init(); if (retval != ERROR_OK) { LOG_DEBUG("can't init SWD driver"); return retval; } /* force DAP into SWD mode (not JTAG) */ - retval = dap_to_swd(target); + /*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; } @@ -315,10 +402,13 @@ 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; + 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)? @@ -329,15 +419,17 @@ struct adiv5_dap *dap = arm->dap; /* Note, debugport_init() does setup too */ - uint8_t ack; + swd_queue_dp_read(dap, DP_IDCODE, &idcode); + + /* force clear all sticky faults */ + swd_clear_sticky_errors(dap); - status = swd_queue_idcode_read(dap, &ack, &idcode); + status = swd_run(dap); if (status == ERROR_OK) - LOG_INFO("SWD IDCODE %#8.8x", idcode); + LOG_INFO("SWD IDCODE %#8.8" PRIx32, idcode); return status; - } static struct transport swd_transport = {