*/
#define MAX_WAIT_RETRIES 8
+/* HLA is currently limited at AP#0 and no control on CSW */
+#define STLINK_HLA_AP_NUM 0
+#define STLINK_HLA_CSW 0
+
enum stlink_jtag_api_version {
STLINK_JTAG_API_V1 = 1,
STLINK_JTAG_API_V2,
int (*read_trace)(void *handle, const uint8_t *buf, int size);
};
+/* TODO: make queue size dynamic */
+/* TODO: don't allocate queue for HLA */
+#define MAX_QUEUE_DEPTH (4096)
+
+enum queue_cmd {
+ CMD_DP_READ = 1,
+ CMD_DP_WRITE,
+
+ CMD_AP_READ,
+ CMD_AP_WRITE,
+
+ /*
+ * encode the bytes size in the enum's value. This makes easy to extract it
+ * with a simple logic AND, by using the macro CMD_MEM_AP_2_SIZE() below
+ */
+ CMD_MEM_AP_READ8 = 0x10 + 1,
+ CMD_MEM_AP_READ16 = 0x10 + 2,
+ CMD_MEM_AP_READ32 = 0x10 + 4,
+
+ CMD_MEM_AP_WRITE8 = 0x20 + 1,
+ CMD_MEM_AP_WRITE16 = 0x20 + 2,
+ CMD_MEM_AP_WRITE32 = 0x20 + 4,
+};
+
+#define CMD_MEM_AP_2_SIZE(cmd) ((cmd) & 7)
+
+struct dap_queue {
+ enum queue_cmd cmd;
+ union {
+ struct dp_r {
+ unsigned int reg;
+ struct adiv5_dap *dap;
+ uint32_t *p_data;
+ } dp_r;
+ struct dp_w {
+ unsigned int reg;
+ struct adiv5_dap *dap;
+ uint32_t data;
+ } dp_w;
+ struct ap_r {
+ unsigned int reg;
+ struct adiv5_ap *ap;
+ uint32_t *p_data;
+ } ap_r;
+ struct ap_w {
+ unsigned int reg;
+ struct adiv5_ap *ap;
+ uint32_t data;
+ } ap_w;
+ struct mem_ap {
+ uint32_t addr;
+ struct adiv5_ap *ap;
+ union {
+ uint32_t *p_data;
+ uint32_t data;
+ };
+ uint32_t csw;
+ } mem_ap;
+ };
+};
+
/** */
struct stlink_usb_handle_s {
/** */
/** reconnect is needed next time we try to query the
* status */
bool reconnect_pending;
+ /** queue of dap_direct operations */
+ struct dap_queue queue[MAX_QUEUE_DEPTH];
+ /** first element available in the queue */
+ unsigned int queue_index;
};
/** */
/* aliases */
#define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE
#define STLINK_F_HAS_FPU_REG STLINK_F_HAS_GETLASTRWSTATUS2
+#define STLINK_F_HAS_CSW STLINK_F_HAS_DPBANKSEL
#define STLINK_REGSEL_IS_FPU(x) ((x) > 0x1F)
flags |= STLINK_F_FIX_CLOSE_AP;
/* Banked regs (DPv1 & DPv2) support from V2J32 */
+ /* Memory R/W supports CSW from V2J32 */
if (h->version.jtag >= 32)
flags |= STLINK_F_HAS_DPBANKSEL;
flags |= STLINK_F_FIX_CLOSE_AP;
/* Banked regs (DPv1 & DPv2) support from V3J2 */
+ /* Memory R/W supports CSW from V3J2 */
if (h->version.jtag >= 2)
flags |= STLINK_F_HAS_DPBANKSEL;
}
/** */
-static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
- uint8_t *buffer)
+static int stlink_usb_read_mem8(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint16_t len, uint8_t *buffer)
{
int res;
uint16_t read_len = len;
assert(handle);
+ if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+ return ERROR_COMMAND_NOTFOUND;
+
/* max 8 bit read/write is 64 bytes or 512 bytes for v3 */
if (len > stlink_usb_block(h)) {
LOG_DEBUG("max buffer (%d) length exceeded", stlink_usb_block(h));
h->cmdidx += 4;
h_u16_to_le(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+ h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+ h->cmdidx += 3;
/* we need to fix read length for single bytes */
if (read_len == 1)
}
/** */
-static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
- const uint8_t *buffer)
+static int stlink_usb_write_mem8(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint16_t len, const uint8_t *buffer)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle);
+ if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+ return ERROR_COMMAND_NOTFOUND;
+
/* max 8 bit read/write is 64 bytes or 512 bytes for v3 */
if (len > stlink_usb_block(h)) {
LOG_DEBUG("max buffer length (%d) exceeded", stlink_usb_block(h));
h->cmdidx += 4;
h_u16_to_le(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+ h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+ h->cmdidx += 3;
res = stlink_usb_xfer_noerrcheck(handle, buffer, len);
}
/** */
-static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len,
- uint8_t *buffer)
+static int stlink_usb_read_mem16(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint16_t len, uint8_t *buffer)
{
int res;
struct stlink_usb_handle_s *h = handle;
if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT))
return ERROR_COMMAND_NOTFOUND;
+ if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+ return ERROR_COMMAND_NOTFOUND;
+
if (len > STLINK_MAX_RW16_32) {
LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
return ERROR_FAIL;
h->cmdidx += 4;
h_u16_to_le(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+ h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+ h->cmdidx += 3;
res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len);
}
/** */
-static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len,
- const uint8_t *buffer)
+static int stlink_usb_write_mem16(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint16_t len, const uint8_t *buffer)
{
int res;
struct stlink_usb_handle_s *h = handle;
if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT))
return ERROR_COMMAND_NOTFOUND;
+ if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+ return ERROR_COMMAND_NOTFOUND;
+
if (len > STLINK_MAX_RW16_32) {
LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
return ERROR_FAIL;
h->cmdidx += 4;
h_u16_to_le(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+ h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+ h->cmdidx += 3;
res = stlink_usb_xfer_noerrcheck(handle, buffer, len);
}
/** */
-static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
- uint8_t *buffer)
+static int stlink_usb_read_mem32(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint16_t len, uint8_t *buffer)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle);
+ if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+ return ERROR_COMMAND_NOTFOUND;
+
if (len > STLINK_MAX_RW16_32) {
LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
return ERROR_FAIL;
h->cmdidx += 4;
h_u16_to_le(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+ h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+ h->cmdidx += 3;
res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len);
}
/** */
-static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
- const uint8_t *buffer)
+static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint16_t len, const uint8_t *buffer)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle);
+ if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+ return ERROR_COMMAND_NOTFOUND;
+
if (len > STLINK_MAX_RW16_32) {
LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
return ERROR_FAIL;
h->cmdidx += 4;
h_u16_to_le(h->cmdbuf+h->cmdidx, len);
h->cmdidx += 2;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+ h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+ h->cmdidx += 3;
res = stlink_usb_xfer_noerrcheck(handle, buffer, len);
return max_tar_block;
}
-static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
- uint32_t count, uint8_t *buffer)
+static int stlink_usb_read_ap_mem(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer)
{
int retval = ERROR_OK;
uint32_t bytes_remaining;
size = 1;
while (count) {
-
bytes_remaining = (size != 1) ?
stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h);
* as 8bit access.
*/
if (size != 1) {
-
/* When in jtag mode the stlink uses the auto-increment functionality.
* However it expects us to pass the data correctly, this includes
* alignment and any page boundaries. We already do this as part of the
/* we first need to check for any unaligned bytes */
if (addr & (size - 1)) {
-
uint32_t head_bytes = size - (addr & (size - 1));
- retval = stlink_usb_read_mem8(handle, addr, head_bytes, buffer);
+ retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, head_bytes, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
- usleep((1<<retries++) * 1000);
+ usleep((1 << retries++) * 1000);
continue;
}
if (retval != ERROR_OK)
}
if (bytes_remaining & (size - 1))
- retval = stlink_usb_read_mem(handle, addr, 1, bytes_remaining, buffer);
+ retval = stlink_usb_read_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer);
else if (size == 2)
- retval = stlink_usb_read_mem16(handle, addr, bytes_remaining, buffer);
+ retval = stlink_usb_read_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer);
else
- retval = stlink_usb_read_mem32(handle, addr, bytes_remaining, buffer);
- } else
- retval = stlink_usb_read_mem8(handle, addr, bytes_remaining, buffer);
+ retval = stlink_usb_read_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer);
+ } else {
+ retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer);
+ }
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
- usleep((1<<retries++) * 1000);
+ usleep((1 << retries++) * 1000);
continue;
}
if (retval != ERROR_OK)
return retval;
}
-static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
- uint32_t count, const uint8_t *buffer)
+static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
+ uint32_t count, uint8_t *buffer)
+{
+ return stlink_usb_read_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW,
+ addr, size, count, buffer);
+}
+
+static int stlink_usb_write_ap_mem(void *handle, uint8_t ap_num, uint32_t csw,
+ uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer)
{
int retval = ERROR_OK;
uint32_t bytes_remaining;
if (addr & (size - 1)) {
uint32_t head_bytes = size - (addr & (size - 1));
- retval = stlink_usb_write_mem8(handle, addr, head_bytes, buffer);
+ retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, head_bytes, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
}
if (bytes_remaining & (size - 1))
- retval = stlink_usb_write_mem(handle, addr, 1, bytes_remaining, buffer);
+ retval = stlink_usb_write_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer);
else if (size == 2)
- retval = stlink_usb_write_mem16(handle, addr, bytes_remaining, buffer);
+ retval = stlink_usb_write_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer);
else
- retval = stlink_usb_write_mem32(handle, addr, bytes_remaining, buffer);
+ retval = stlink_usb_write_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer);
} else
- retval = stlink_usb_write_mem8(handle, addr, bytes_remaining, buffer);
+ retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
return retval;
}
+static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
+ uint32_t count, const uint8_t *buffer)
+{
+ return stlink_usb_write_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW,
+ addr, size, count, buffer);
+}
+
/** */
static int stlink_usb_override_target(const char *targetname)
{
h->max_mem_packet = (1 << 10);
uint8_t buffer[4];
- stlink_usb_open_ap(h, 0);
- err = stlink_usb_read_mem32(h, CPUID, 4, buffer);
+ stlink_usb_open_ap(h, STLINK_HLA_AP_NUM);
+ err = stlink_usb_read_mem32(h, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, CPUID, 4, buffer);
if (err == ERROR_OK) {
uint32_t cpuid = le_to_h_u32(buffer);
int i = (cpuid >> 4) & 0xf;
static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1);
static int stlink_dap_error = ERROR_OK;
-static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
- uint32_t *data);
-
/** */
static int stlink_dap_record_error(int error)
{
return retval;
}
+static int stlink_dap_get_error(void)
+{
+ return stlink_dap_error;
+}
+
static int stlink_usb_open_ap(void *handle, unsigned short apsel)
{
struct stlink_usb_handle_s *h = handle;
}
/** */
-static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
- uint32_t *data)
+static int stlink_dap_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data)
{
uint32_t dummy;
int retval;
return ERROR_COMMAND_NOTFOUND;
}
- retval = stlink_dap_check_reconnect(dap);
- if (retval != ERROR_OK)
- return retval;
-
data = data ? data : &dummy;
if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ
&& stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) {
STLINK_DEBUG_PORT_ACCESS, reg, data);
}
- return stlink_dap_record_error(retval);
+ return retval;
}
/** */
-static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
- uint32_t data)
+static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data)
{
int retval;
data &= ~DP_SELECT_DPBANK;
}
- retval = stlink_dap_check_reconnect(dap);
- if (retval != ERROR_OK)
- return retval;
-
/* ST-Link does not like that we set CORUNDETECT */
if (reg == DP_CTRL_STAT)
data &= ~CORUNDETECT;
retval = stlink_write_dap_register(stlink_dap_handle,
STLINK_DEBUG_PORT_ACCESS, reg, data);
- return stlink_dap_record_error(retval);
+ return retval;
}
/** */
-static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned reg,
- uint32_t *data)
+static int stlink_dap_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data)
{
struct adiv5_dap *dap = ap->dap;
uint32_t dummy;
int retval;
- retval = stlink_dap_check_reconnect(dap);
- if (retval != ERROR_OK)
- return retval;
-
if (reg != AP_REG_IDR) {
retval = stlink_dap_open_ap(ap->ap_num);
if (retval != ERROR_OK)
retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg,
data);
dap->stlink_flush_ap_write = false;
- return stlink_dap_record_error(retval);
+ return retval;
}
/** */
-static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned reg,
- uint32_t data)
+static int stlink_dap_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data)
{
struct adiv5_dap *dap = ap->dap;
int retval;
- retval = stlink_dap_check_reconnect(dap);
- if (retval != ERROR_OK)
- return retval;
-
retval = stlink_dap_open_ap(ap->ap_num);
if (retval != ERROR_OK)
return retval;
retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg,
data);
dap->stlink_flush_ap_write = true;
- return stlink_dap_record_error(retval);
+ return retval;
}
/** */
return ERROR_OK;
}
+static int stlink_usb_buf_rw_segment(void *handle, const struct dap_queue *q, unsigned int count)
+{
+ uint32_t bufsize = count * CMD_MEM_AP_2_SIZE(q[0].cmd);
+ uint8_t buf[bufsize];
+ uint8_t ap_num = q[0].mem_ap.ap->ap_num;
+ uint32_t addr = q[0].mem_ap.addr;
+ uint32_t csw = q[0].mem_ap.csw;
+
+ int retval = stlink_dap_open_ap(ap_num);
+ if (retval != ERROR_OK)
+ return retval;
+
+ switch (q[0].cmd) {
+ case CMD_MEM_AP_WRITE8:
+ for (unsigned int i = 0; i < count; i++)
+ buf[i] = q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 3);
+ return stlink_usb_write_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+
+ case CMD_MEM_AP_WRITE16:
+ for (unsigned int i = 0; i < count; i++)
+ h_u16_to_le(&buf[2 * i], q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 2));
+ return stlink_usb_write_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+
+ case CMD_MEM_AP_WRITE32:
+ for (unsigned int i = 0; i < count; i++)
+ h_u32_to_le(&buf[4 * i], q[i].mem_ap.data);
+ return stlink_usb_write_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+
+ case CMD_MEM_AP_READ8:
+ retval = stlink_usb_read_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+ if (retval == ERROR_OK)
+ for (unsigned int i = 0; i < count; i++)
+ *q[i].mem_ap.p_data = buf[i] << 8 * (q[i].mem_ap.addr & 3);
+ return retval;
+
+ case CMD_MEM_AP_READ16:
+ retval = stlink_usb_read_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+ if (retval == ERROR_OK)
+ for (unsigned int i = 0; i < count; i++)
+ *q[i].mem_ap.p_data = le_to_h_u16(&buf[2 * i]) << 8 * (q[i].mem_ap.addr & 2);
+ return retval;
+
+ case CMD_MEM_AP_READ32:
+ retval = stlink_usb_read_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+ if (retval == ERROR_OK)
+ for (unsigned int i = 0; i < count; i++)
+ *q[i].mem_ap.p_data = le_to_h_u32(&buf[4 * i]);
+ return retval;
+
+ default:
+ return ERROR_FAIL;
+ };
+}
+
+static int stlink_usb_count_buf_rw_queue(const struct dap_queue *q, unsigned int len)
+{
+ uint32_t incr = CMD_MEM_AP_2_SIZE(q[0].cmd);
+ unsigned int len_max;
+
+ if (incr == 1)
+ len_max = stlink_usb_block(stlink_dap_handle);
+ else
+ len_max = STLINK_MAX_RW16_32 / incr;
+
+ if (len > len_max)
+ len = len_max;
+
+ for (unsigned int i = 1; i < len; i++)
+ if (q[i].cmd != q[0].cmd ||
+ q[i].mem_ap.ap != q[0].mem_ap.ap ||
+ q[i].mem_ap.csw != q[0].mem_ap.csw ||
+ q[i].mem_ap.addr != q[i - 1].mem_ap.addr + incr)
+ return i;
+
+ return len;
+}
+
+static int stlink_usb_mem_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, unsigned int *skip)
+{
+ unsigned int count = stlink_usb_count_buf_rw_queue(q, len);
+
+ int retval = stlink_usb_buf_rw_segment(handle, q, count);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *skip = count;
+ return ERROR_OK;
+}
+
+static void stlink_dap_run_internal(struct adiv5_dap *dap)
+{
+ int retval = stlink_dap_check_reconnect(dap);
+ if (retval != ERROR_OK) {
+ stlink_dap_handle->queue_index = 0;
+ stlink_dap_record_error(retval);
+ return;
+ }
+
+ unsigned int i = stlink_dap_handle->queue_index;
+ struct dap_queue *q = &stlink_dap_handle->queue[0];
+
+ while (i && stlink_dap_get_error() == ERROR_OK) {
+ unsigned int skip = 1;
+
+ switch (q->cmd) {
+ case CMD_DP_READ:
+ retval = stlink_dap_dp_read(q->dp_r.dap, q->dp_r.reg, q->dp_r.p_data);
+ break;
+ case CMD_DP_WRITE:
+ retval = stlink_dap_dp_write(q->dp_w.dap, q->dp_w.reg, q->dp_w.data);
+ break;
+ case CMD_AP_READ:
+ retval = stlink_dap_ap_read(q->ap_r.ap, q->ap_r.reg, q->ap_r.p_data);
+ break;
+ case CMD_AP_WRITE:
+ /* ignore increment packed, not supported */
+ if (q->ap_w.reg == MEM_AP_REG_CSW)
+ q->ap_w.data &= ~CSW_ADDRINC_PACKED;
+ retval = stlink_dap_ap_write(q->ap_w.ap, q->ap_w.reg, q->ap_w.data);
+ break;
+
+ case CMD_MEM_AP_READ8:
+ case CMD_MEM_AP_READ16:
+ case CMD_MEM_AP_READ32:
+ case CMD_MEM_AP_WRITE8:
+ case CMD_MEM_AP_WRITE16:
+ case CMD_MEM_AP_WRITE32:
+ retval = stlink_usb_mem_rw_queue(stlink_dap_handle, q, i, &skip);
+ break;
+
+ default:
+ LOG_ERROR("ST-Link: Unknown queue command %d", q->cmd);
+ retval = ERROR_FAIL;
+ break;
+ }
+ stlink_dap_record_error(retval);
+ q += skip;
+ i -= skip;
+ }
+
+ stlink_dap_handle->queue_index = 0;
+}
+
/** */
-static int stlink_dap_op_run(struct adiv5_dap *dap)
+static int stlink_dap_run_finalize(struct adiv5_dap *dap)
{
uint32_t ctrlstat, pwrmask;
int retval, saved_retval;
*/
if (dap->stlink_flush_ap_write) {
dap->stlink_flush_ap_write = false;
- retval = stlink_dap_op_queue_dp_read(dap, DP_RDBUFF, NULL);
+ retval = stlink_dap_dp_read(dap, DP_RDBUFF, NULL);
if (retval != ERROR_OK) {
dap->do_reconnect = true;
return retval;
saved_retval = stlink_dap_get_and_clear_error();
- retval = stlink_dap_op_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
- if (retval != ERROR_OK) {
- dap->do_reconnect = true;
- return retval;
- }
- retval = stlink_dap_get_and_clear_error();
+ retval = stlink_dap_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
if (retval != ERROR_OK) {
LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect");
dap->do_reconnect = true;
if (ctrlstat & SSTICKYERR) {
if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG)
- retval = stlink_dap_op_queue_dp_write(dap, DP_CTRL_STAT,
+ retval = stlink_dap_dp_write(dap, DP_CTRL_STAT,
ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR));
else
- retval = stlink_dap_op_queue_dp_write(dap, DP_ABORT, STKERRCLR);
- if (retval != ERROR_OK) {
- dap->do_reconnect = true;
- return retval;
- }
- retval = stlink_dap_get_and_clear_error();
+ retval = stlink_dap_dp_write(dap, DP_ABORT, STKERRCLR);
if (retval != ERROR_OK) {
dap->do_reconnect = true;
return retval;
return saved_retval;
}
+static int stlink_dap_op_queue_run(struct adiv5_dap *dap)
+{
+ stlink_dap_run_internal(dap);
+ return stlink_dap_run_finalize(dap);
+}
+
/** */
static void stlink_dap_op_quit(struct adiv5_dap *dap)
{
LOG_ERROR("Error closing APs");
}
+static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned int reg,
+ uint32_t *data)
+{
+ if (stlink_dap_get_error() != ERROR_OK)
+ return ERROR_OK;
+
+ unsigned int i = stlink_dap_handle->queue_index++;
+ struct dap_queue *q = &stlink_dap_handle->queue[i];
+ q->cmd = CMD_DP_READ;
+ q->dp_r.reg = reg;
+ q->dp_r.dap = dap;
+ q->dp_r.p_data = data;
+
+ if (i == MAX_QUEUE_DEPTH - 1)
+ stlink_dap_run_internal(dap);
+
+ return ERROR_OK;
+}
+
+static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned int reg,
+ uint32_t data)
+{
+ if (stlink_dap_get_error() != ERROR_OK)
+ return ERROR_OK;
+
+ unsigned int i = stlink_dap_handle->queue_index++;
+ struct dap_queue *q = &stlink_dap_handle->queue[i];
+ q->cmd = CMD_DP_WRITE;
+ q->dp_w.reg = reg;
+ q->dp_w.dap = dap;
+ q->dp_w.data = data;
+
+ if (i == MAX_QUEUE_DEPTH - 1)
+ stlink_dap_run_internal(dap);
+
+ return ERROR_OK;
+}
+
+static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg,
+ uint32_t *data)
+{
+ if (stlink_dap_get_error() != ERROR_OK)
+ return ERROR_OK;
+
+ unsigned int i = stlink_dap_handle->queue_index++;
+ struct dap_queue *q = &stlink_dap_handle->queue[i];
+
+ if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) &&
+ (reg == MEM_AP_REG_DRW || reg == MEM_AP_REG_BD0 || reg == MEM_AP_REG_BD1 ||
+ reg == MEM_AP_REG_BD2 || reg == MEM_AP_REG_BD3)) {
+ /* de-queue previous write-TAR */
+ struct dap_queue *prev_q = q - 1;
+ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_TAR) {
+ stlink_dap_handle->queue_index = i;
+ i--;
+ q = prev_q;
+ prev_q--;
+ }
+ /* de-queue previous write-CSW */
+ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW) {
+ stlink_dap_handle->queue_index = i;
+ q = prev_q;
+ }
+
+ switch (ap->csw_value & CSW_SIZE_MASK) {
+ case CSW_8BIT:
+ q->cmd = CMD_MEM_AP_READ8;
+ break;
+ case CSW_16BIT:
+ q->cmd = CMD_MEM_AP_READ16;
+ break;
+ case CSW_32BIT:
+ q->cmd = CMD_MEM_AP_READ32;
+ break;
+ default:
+ LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK);
+ stlink_dap_record_error(ERROR_FAIL);
+ return ERROR_FAIL;
+ }
+
+ q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c));
+ q->mem_ap.ap = ap;
+ q->mem_ap.p_data = data;
+ q->mem_ap.csw = ap->csw_default;
+
+ /* force TAR and CSW update */
+ ap->tar_valid = false;
+ ap->csw_value = 0;
+ } else {
+ q->cmd = CMD_AP_READ;
+ q->ap_r.reg = reg;
+ q->ap_r.ap = ap;
+ q->ap_r.p_data = data;
+ }
+
+ if (i == MAX_QUEUE_DEPTH - 1)
+ stlink_dap_run_internal(ap->dap);
+
+ return ERROR_OK;
+}
+
+static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg,
+ uint32_t data)
+{
+ if (stlink_dap_get_error() != ERROR_OK)
+ return ERROR_OK;
+
+ unsigned int i = stlink_dap_handle->queue_index++;
+ struct dap_queue *q = &stlink_dap_handle->queue[i];
+
+ if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) &&
+ (reg == MEM_AP_REG_DRW || reg == MEM_AP_REG_BD0 || reg == MEM_AP_REG_BD1 ||
+ reg == MEM_AP_REG_BD2 || reg == MEM_AP_REG_BD3)) {
+ /* de-queue previous write-TAR */
+ struct dap_queue *prev_q = q - 1;
+ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_TAR) {
+ stlink_dap_handle->queue_index = i;
+ i--;
+ q = prev_q;
+ prev_q--;
+ }
+ /* de-queue previous write-CSW */
+ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW) {
+ stlink_dap_handle->queue_index = i;
+ q = prev_q;
+ }
+
+ switch (ap->csw_value & CSW_SIZE_MASK) {
+ case CSW_8BIT:
+ q->cmd = CMD_MEM_AP_WRITE8;
+ break;
+ case CSW_16BIT:
+ q->cmd = CMD_MEM_AP_WRITE16;
+ break;
+ case CSW_32BIT:
+ q->cmd = CMD_MEM_AP_WRITE32;
+ break;
+ default:
+ LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK);
+ stlink_dap_record_error(ERROR_FAIL);
+ return ERROR_FAIL;
+ }
+
+ q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c));
+ q->mem_ap.ap = ap;
+ q->mem_ap.data = data;
+ q->mem_ap.csw = ap->csw_default;
+
+ /* force TAR and CSW update */
+ ap->tar_valid = false;
+ ap->csw_value = 0;
+ } else {
+ q->cmd = CMD_AP_WRITE;
+ q->ap_w.reg = reg;
+ q->ap_w.ap = ap;
+ q->ap_w.data = data;
+ }
+
+ if (i == MAX_QUEUE_DEPTH - 1)
+ stlink_dap_run_internal(ap->dap);
+
+ return ERROR_OK;
+}
+
static int stlink_swim_op_srst(void)
{
return stlink_swim_generate_rst(stlink_dap_handle);
.queue_ap_read = stlink_dap_op_queue_ap_read,
.queue_ap_write = stlink_dap_op_queue_ap_write,
.queue_ap_abort = stlink_dap_op_queue_ap_abort,
- .run = stlink_dap_op_run,
+ .run = stlink_dap_op_queue_run,
.sync = NULL, /* optional */
.quit = stlink_dap_op_quit, /* optional */
};