swd: Convert API to asynchronous

Change-Id: I859568dbb2ad4e92411980751c3f747bd70638b8
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1959
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
This commit is contained in:
Andreas Fritiofson 2014-06-19 00:47:17 +02:00
parent 2268b77142
commit d2bb14e36a
5 changed files with 159 additions and 189 deletions

View File

@ -479,8 +479,13 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
} }
#endif #endif
static int cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value) static int queued_retval;
static void cmsis_dap_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
{ {
if (queued_retval != ERROR_OK)
return;
uint8_t *buffer = cmsis_dap_handle->packet_buffer; uint8_t *buffer = cmsis_dap_handle->packet_buffer;
int retval; int retval;
uint32_t val; uint32_t val;
@ -497,7 +502,8 @@ static int cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value)
/* TODO - need better response checking */ /* TODO - need better response checking */
if (retval != ERROR_OK || buffer[1] != 0x01) { if (retval != ERROR_OK || buffer[1] != 0x01) {
LOG_ERROR("CMSIS-DAP: Read Error (0x%02" PRIx8 ")", buffer[2]); LOG_ERROR("CMSIS-DAP: Read Error (0x%02" PRIx8 ")", buffer[2]);
return buffer[2]; queued_retval = buffer[2];
return;
} }
val = le_to_h_u32(&buffer[3]); val = le_to_h_u32(&buffer[3]);
@ -506,11 +512,14 @@ static int cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value)
if (value) if (value)
*value = val; *value = val;
return retval; queued_retval = retval;
} }
static int cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value) static void cmsis_dap_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
{ {
if (queued_retval != ERROR_OK)
return;
uint8_t *buffer = cmsis_dap_handle->packet_buffer; uint8_t *buffer = cmsis_dap_handle->packet_buffer;
DEBUG_IO("CMSIS-DAP: Write Reg 0x%02" PRIx8 " 0x%08" PRIx32, cmd, value); DEBUG_IO("CMSIS-DAP: Write Reg 0x%02" PRIx8 " 0x%08" PRIx32, cmd, value);
@ -531,6 +540,13 @@ static int cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value)
retval = buffer[2]; retval = buffer[2];
} }
queued_retval = retval;
}
static int cmsis_dap_swd_run(struct adiv5_dap *dap)
{
int retval = queued_retval;
queued_retval = ERROR_OK;
return retval; return retval;
} }
@ -994,9 +1010,10 @@ static const struct command_registration cmsis_dap_command_handlers[] = {
}; };
static const struct swd_driver cmsis_dap_swd_driver = { static const struct swd_driver cmsis_dap_swd_driver = {
.init = cmsis_dap_swd_init, .init = cmsis_dap_swd_init,
.read_reg = cmsis_dap_swd_read_reg, .read_reg = cmsis_dap_swd_read_reg,
.write_reg = cmsis_dap_swd_write_reg, .write_reg = cmsis_dap_swd_write_reg,
.run = cmsis_dap_swd_run,
}; };
const char *cmsis_dap_transport[] = {"cmsis-dap", NULL}; const char *cmsis_dap_transport[] = {"cmsis-dap", NULL};

View File

@ -20,6 +20,8 @@
#ifndef SWD_H #ifndef SWD_H
#define SWD_H #define SWD_H
#include <target/arm_adi_v5.h>
/* Bits in SWD command packets, written from host to target /* Bits in SWD command packets, written from host to target
* first bit on the wire is START * first bit on the wire is START
*/ */
@ -53,51 +55,47 @@ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum)
/* SWD_ACK_* bits are defined in <target/arm_adi_v5.h> */ /* SWD_ACK_* bits are defined in <target/arm_adi_v5.h> */
/*
* FOR NOW ... SWD driver ops are synchronous and return ACK
* status ... no queuing.
*
* Individual ops are request/response, and fast-fail permits much
* better fault handling. Upper layers may queue if desired.
*/
struct swd_driver { struct swd_driver {
/** /**
* Initialize the debug link so it can perform * Initialize the debug link so it can perform SWD operations.
* synchronous SWD operations.
* @param trn value from WCR: how many clocks * @param trn value from WCR: how many clocks
* to not drive the SWDIO line at certain points in * to not drive the SWDIO line at certain points in
* the SWD protocol (at least 1 clock). * the SWD protocol (at least 1 clock).
* *
* As an example, this would switch a dual-mode debug adapter * As an example, this would switch a dual-mode debug adapter
* into SWD mode and out of JTAG mode. * into SWD mode and out of JTAG mode.
* *
* @return ERROR_OK on success, else a negative fault code. * @return ERROR_OK on success, else a negative fault code.
*/ */
int (*init)(uint8_t trn); int (*init)(uint8_t trn);
/** /**
* Synchronous read of an AP or DP register. * Queued read of an AP or DP register.
* *
* @param cmd with APnDP/RnW/addr/parity bits * @param dap The DAP controlled by the SWD link.
* @param where to store value to read from register * @param Command byte with APnDP/RnW/addr/parity bits
* * @param Where to store value to read from register
* @return SWD_ACK_* code for the transaction */
* or (negative) fault code void (*read_reg)(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value);
*/
int (*read_reg)(uint8_t cmd, uint32_t *value);
/** /**
* Synchronous write of an AP or DP register. * Queued write of an AP or DP register.
* *
* @param cmd with APnDP/RnW/addr/parity bits * @param dap The DAP controlled by the SWD link.
* @param value to be written to the register * @param Command byte with APnDP/RnW/addr/parity bits
* * @param Value to be written to the register
* @return SWD_ACK_* code for the transaction */
* or (negative) fault code void (*write_reg)(struct adiv5_dap *dap, uint8_t cmd, uint32_t value);
*/
int (*write_reg)(uint8_t cmd, uint32_t value); /**
* Execute any queued transactions and collect the result.
*
* @param dap The DAP controlled by the SWD link.
* @return ERROR_OK on success, Ack response code on WAIT/FAULT
* or negative error code on other kinds of failure.
*/
int (*run)(struct adiv5_dap *dap);
/** /**
* Configures data collection from the Single-wire * Configures data collection from the Single-wire
@ -108,10 +106,10 @@ struct swd_driver {
* is normally connected to a microcontroller's UART TX, * is normally connected to a microcontroller's UART TX,
* but which may instead be connected to SWO for use in * but which may instead be connected to SWO for use in
* collecting ITM (and possibly ETM) trace data. * collecting ITM (and possibly ETM) trace data.
* *
* @return ERROR_OK on success, else a negative fault code. * @return ERROR_OK on success, else a negative fault code.
*/ */
int *(*trace)(bool swo); int *(*trace)(struct adiv5_dap *dap, bool swo);
}; };
int swd_init_reset(struct command_context *cmd_ctx); int swd_init_reset(struct command_context *cmd_ctx);

View File

@ -61,8 +61,9 @@ static int cmsis_dap_clear_sticky_errors(struct adiv5_dap *dap)
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
return swd->write_reg(swd_cmd(false, false, DP_ABORT), swd->write_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(DP_ABORT)),
STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
return ERROR_OK;
} }
static int cmsis_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) static int cmsis_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
@ -72,21 +73,20 @@ static int cmsis_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
return swd->write_reg(swd_cmd(false, false, DP_ABORT), swd->write_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(DP_ABORT)),
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
return ERROR_OK;
} }
static int cmsis_dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) static int cmsis_dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
{ {
LOG_DEBUG("reg = %d", reg); LOG_DEBUG("reg = %d", reg);
int retval = jtag_interface->swd->read_reg( const struct swd_driver *swd = jtag_interface->swd;
(CMSIS_CMD_DP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data); assert(swd);
if (retval != ERROR_OK) swd->read_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
cmsis_dap_clear_sticky_errors(dap); return ERROR_OK;
return retval;
} }
static int (cmsis_dap_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) static int (cmsis_dap_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
@ -100,13 +100,11 @@ static int (cmsis_dap_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint3
data &= ~CORUNDETECT; data &= ~CORUNDETECT;
} }
int retval = jtag_interface->swd->write_reg( const struct swd_driver *swd = jtag_interface->swd;
(CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data); assert(swd);
if (retval != ERROR_OK) swd->write_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
cmsis_dap_clear_sticky_errors(dap); return ERROR_OK;
return retval;
} }
/** Select the AP register bank matching bits 7:4 of reg. */ /** Select the AP register bank matching bits 7:4 of reg. */
@ -120,58 +118,47 @@ static int cmsis_dap_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
dap->ap_bank_value = select_ap_bank; dap->ap_bank_value = select_ap_bank;
select_ap_bank |= dap->ap_current; select_ap_bank |= dap->ap_current;
return cmsis_dap_queue_dp_write(dap, DP_SELECT, select_ap_bank); cmsis_dap_queue_dp_write(dap, DP_SELECT, select_ap_bank);
return ERROR_OK;
} }
static int (cmsis_dap_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data) static int (cmsis_dap_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
{ {
int retval = cmsis_dap_ap_q_bankselect(dap, reg); cmsis_dap_ap_q_bankselect(dap, reg);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("reg = %d", reg); LOG_DEBUG("reg = %d", reg);
retval = jtag_interface->swd->read_reg( const struct swd_driver *swd = jtag_interface->swd;
(CMSIS_CMD_AP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data); assert(swd);
if (retval != ERROR_OK) swd->read_reg(dap, (CMSIS_CMD_AP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
cmsis_dap_clear_sticky_errors(dap);
return retval; return ERROR_OK;
} }
static int (cmsis_dap_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) static int (cmsis_dap_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
{ {
/* TODO: CSW_DBGSWENABLE (bit31) causes issues for some targets /* TODO: CSW_DBGSWENABLE (bit31) causes issues for some targets
* disable until we find out why */ * disable until we find out why */
if (reg == AP_REG_CSW) if (reg == AP_REG_CSW)
data &= ~CSW_DBGSWENABLE; data &= ~CSW_DBGSWENABLE;
int retval = cmsis_dap_ap_q_bankselect(dap, reg); cmsis_dap_ap_q_bankselect(dap, reg);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("reg = %d, data = 0x%08" PRIx32, reg, data); LOG_DEBUG("reg = %d, data = 0x%08" PRIx32, reg, data);
retval = jtag_interface->swd->write_reg( const struct swd_driver *swd = jtag_interface->swd;
(CMSIS_CMD_AP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data); assert(swd);
if (retval != ERROR_OK) swd->write_reg(dap, (CMSIS_CMD_AP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
cmsis_dap_clear_sticky_errors(dap);
return retval; return ERROR_OK;
} }
/** Executes all queued DAP operations. */ /** Executes all queued DAP operations. */
static int cmsis_dap_run(struct adiv5_dap *dap) static int cmsis_dap_run(struct adiv5_dap *dap)
{ {
LOG_DEBUG(" "); LOG_DEBUG(" ");
/* FIXME: for now the CMSIS-DAP interface hard-wires a zero-size queue. */
int ret;
uint32_t ctrlstat;
/* /*
Some debug dongles do more than asked for(e.g. EDBG from Some debug dongles do more than asked for(e.g. EDBG from
Atmel) behind the scene and issuing an AP write Atmel) behind the scene and issuing an AP write
@ -182,23 +169,22 @@ static int cmsis_dap_run(struct adiv5_dap *dap)
differently and not guarantee to be report those failures differently and not guarantee to be report those failures
via status byte of the return USB packet from CMSIS-DAP, so via status byte of the return USB packet from CMSIS-DAP, so
we need to check CTRL/STAT and if that happens to clear it. we need to check CTRL/STAT and if that happens to clear it.
Note that once the CMSIS-DAP SWD implementation starts queueing
transfers this will cause loss of the transfers after the
failed one. At least a warning is printed.
*/ */
ret = cmsis_dap_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); uint32_t ctrlstat;
if (ret != ERROR_OK) { cmsis_dap_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
LOG_ERROR("Failed to read CTRL/STAT register");
return ret;
}
if (ctrlstat & SSTICKYERR) { int retval = jtag_interface->swd->run(dap);
LOG_WARNING("SSTICKYERR was set, clearing it");
ret = cmsis_dap_clear_sticky_errors(dap);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to clear sticky errors");
return ret;
}
}
return ret; if (retval == ERROR_OK && (ctrlstat & SSTICKYERR))
LOG_WARNING("Adapter returned success despite SSTICKYERR being set.");
if (retval != ERROR_OK || (ctrlstat & SSTICKYERR))
cmsis_dap_clear_sticky_errors(dap);
return retval;
} }
const struct dap_ops cmsis_dap_ops = { const struct dap_ops cmsis_dap_ops = {
@ -240,7 +226,7 @@ static const struct command_registration cmsis_dap_handlers[] = {
static int cmsis_dap_select(struct command_context *ctx) static int cmsis_dap_select(struct command_context *ctx)
{ {
LOG_DEBUG(" "); LOG_DEBUG("CMSIS-ADI: cmsis_dap_select");
int retval = register_commands(ctx, NULL, cmsis_dap_handlers); int retval = register_commands(ctx, NULL, cmsis_dap_handlers);

View File

@ -57,179 +57,146 @@
/* YUK! - but this is currently a global.... */ /* YUK! - but this is currently a global.... */
extern struct jtag_interface *jtag_interface; extern struct jtag_interface *jtag_interface;
static bool do_sync;
static int swd_finish_read(struct adiv5_dap *dap) static void swd_finish_read(struct adiv5_dap *dap)
{ {
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
int retval = ERROR_OK;
if (dap->last_read != NULL) { if (dap->last_read != NULL) {
retval = swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read); swd->read_reg(dap, swd_cmd(true, false, DP_RDBUFF), dap->last_read);
dap->last_read = NULL; dap->last_read = NULL;
} }
return retval;
} }
static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
uint32_t data); uint32_t data);
static int swd_clear_sticky_errors(struct adiv5_dap *dap) static void swd_clear_sticky_errors(struct adiv5_dap *dap)
{ {
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
return swd->write_reg(swd_cmd(false, false, DP_ABORT), swd->write_reg(dap, swd_cmd(false, false, DP_ABORT),
STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
} }
static int swd_run_inner(struct adiv5_dap *dap)
{
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 inline int check_sync(struct adiv5_dap *dap)
{
return do_sync ? swd_run_inner(dap) : ERROR_OK;
}
static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) 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 = jtag_interface->swd;
assert(swd); assert(swd);
return swd->write_reg(swd_cmd(false, false, DP_ABORT), swd->write_reg(dap, swd_cmd(false, false, DP_ABORT),
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
return check_sync(dap);
} }
/** Select the DP register bank matching bits 7:4 of reg. */ /** Select the DP register bank matching bits 7:4 of reg. */
static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) static void swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg)
{ {
uint32_t select_dp_bank = (reg & 0x000000F0) >> 4; uint32_t select_dp_bank = (reg & 0x000000F0) >> 4;
if (reg == DP_SELECT) if (reg == DP_SELECT)
return ERROR_OK; return;
if (select_dp_bank == dap->dp_bank_value) if (select_dp_bank == dap->dp_bank_value)
return ERROR_OK; return;
dap->dp_bank_value = select_dp_bank; dap->dp_bank_value = select_dp_bank;
select_dp_bank |= dap->ap_current | dap->ap_bank_value; select_dp_bank |= dap->ap_current | dap->ap_bank_value;
return swd_queue_dp_write(dap, DP_SELECT, select_dp_bank); swd_queue_dp_write(dap, DP_SELECT, select_dp_bank);
} }
static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
uint32_t *data) uint32_t *data)
{ {
int retval;
/* REVISIT status return vs ack ... */
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
retval = swd_queue_dp_bankselect(dap, reg); swd_queue_dp_bankselect(dap, reg);
if (retval != ERROR_OK) swd->read_reg(dap, swd_cmd(true, false, reg), data);
return retval;
retval = swd->read_reg(swd_cmd(true, false, reg), data); return check_sync(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, static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
uint32_t data) uint32_t data)
{ {
int retval;
/* REVISIT status return vs ack ... */
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
retval = swd_finish_read(dap); swd_finish_read(dap);
if (retval != ERROR_OK) swd_queue_dp_bankselect(dap, reg);
return retval; swd->write_reg(dap, swd_cmd(false, false, reg), data);
retval = swd_queue_dp_bankselect(dap, reg); return check_sync(dap);
if (retval != ERROR_OK)
return retval;
retval = swd->write_reg(swd_cmd(false, false, reg), data);
if (retval != ERROR_OK) {
/* fault response */
swd_clear_sticky_errors(dap);
}
return retval;
} }
/** Select the AP register bank matching bits 7:4 of reg. */ /** Select the AP register bank matching bits 7:4 of reg. */
static int swd_queue_ap_bankselect(struct adiv5_dap *dap, unsigned reg) static void swd_queue_ap_bankselect(struct adiv5_dap *dap, unsigned reg)
{ {
uint32_t select_ap_bank = reg & 0x000000F0; uint32_t select_ap_bank = reg & 0x000000F0;
if (select_ap_bank == dap->ap_bank_value) if (select_ap_bank == dap->ap_bank_value)
return ERROR_OK; return;
dap->ap_bank_value = select_ap_bank; dap->ap_bank_value = select_ap_bank;
select_ap_bank |= dap->ap_current | dap->dp_bank_value; select_ap_bank |= dap->ap_current | dap->dp_bank_value;
return swd_queue_dp_write(dap, DP_SELECT, select_ap_bank); swd_queue_dp_write(dap, DP_SELECT, select_ap_bank);
} }
static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, static int swd_queue_ap_read(struct adiv5_dap *dap, unsigned reg,
uint32_t *data) uint32_t *data)
{ {
/* REVISIT status return ... */
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
int retval = swd_queue_ap_bankselect(dap, reg); swd_queue_ap_bankselect(dap, reg);
if (retval != ERROR_OK) swd->read_reg(dap, swd_cmd(true, true, reg), dap->last_read);
return retval;
retval = swd->read_reg(swd_cmd(true, true, reg), dap->last_read);
dap->last_read = data; dap->last_read = data;
if (retval != ERROR_OK) { return check_sync(dap);
/* fault response */
swd_clear_sticky_errors(dap);
return retval;
}
return retval;
} }
static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, static int swd_queue_ap_write(struct adiv5_dap *dap, unsigned reg,
uint32_t data) uint32_t data)
{ {
/* REVISIT status return ... */
const struct swd_driver *swd = jtag_interface->swd; const struct swd_driver *swd = jtag_interface->swd;
assert(swd); assert(swd);
int retval;
retval = swd_finish_read(dap); swd_finish_read(dap);
if (retval != ERROR_OK) swd_queue_ap_bankselect(dap, reg);
return retval; swd->write_reg(dap, swd_cmd(false, true, reg), data);
retval = swd_queue_ap_bankselect(dap, reg); return check_sync(dap);
if (retval != ERROR_OK)
return retval;
retval = swd->write_reg(swd_cmd(false, true, reg), data);
if (retval != ERROR_OK) {
/* fault response */
swd_clear_sticky_errors(dap);
}
return retval;
} }
/** Executes all queued DAP operations. */ /** Executes all queued DAP operations. */
static int swd_run(struct adiv5_dap *dap) static int swd_run(struct adiv5_dap *dap)
{ {
/* for now the SWD interface hard-wires a zero-size queue. */ swd_finish_read(dap);
return swd_run_inner(dap);
int retval = swd_finish_read(dap);
/* FIXME but we still need to check and scrub
* any hardware errors ...
*/
return retval;
} }
const struct dap_ops swd_dap_ops = { const struct dap_ops swd_dap_ops = {
@ -452,14 +419,16 @@ static int swd_init(struct command_context *ctx)
/* Note, debugport_init() does setup too */ /* Note, debugport_init() does setup too */
status = swd_queue_dp_read(dap, DP_IDCODE, &idcode); swd_queue_dp_read(dap, DP_IDCODE, &idcode);
if (status == ERROR_OK)
LOG_INFO("SWD IDCODE %#8.8" PRIx32, idcode);
/* force clear all sticky faults */ /* force clear all sticky faults */
swd_clear_sticky_errors(dap); swd_clear_sticky_errors(dap);
status = swd_run(dap);
if (status == ERROR_OK)
LOG_INFO("SWD IDCODE %#8.8" PRIx32, idcode);
/* this is a workaround to get polling working */ /* this is a workaround to get polling working */
jtag_add_reset(0, 0); jtag_add_reset(0, 0);

View File

@ -40,9 +40,9 @@
#define JTAG_DP_APACC 0xB #define JTAG_DP_APACC 0xB
/* three-bit ACK values for SWD access (sent LSB first) */ /* three-bit ACK values for SWD access (sent LSB first) */
#define SWD_ACK_OK 0x4 #define SWD_ACK_OK 0x1
#define SWD_ACK_WAIT 0x2 #define SWD_ACK_WAIT 0x2
#define SWD_ACK_FAULT 0x1 #define SWD_ACK_FAULT 0x4
#define DPAP_WRITE 0 #define DPAP_WRITE 0
#define DPAP_READ 1 #define DPAP_READ 1