+static int stlink_usb_init_access_port(void *handle, unsigned char ap_num)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle);
+
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_COMMAND_NOTFOUND;
+
+ LOG_DEBUG_IO("init ap_num = %d", ap_num);
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_INIT_AP;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+}
+
+/** */
+static int stlink_usb_close_access_port(void *handle, unsigned char ap_num)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle);
+
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_COMMAND_NOTFOUND;
+
+ LOG_DEBUG_IO("close ap_num = %d", ap_num);
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG;
+ h->cmdbuf[h->cmdidx++] = ap_num;
+
+ /* ignore incorrectly returned error on bogus FW */
+ if (h->version.flags & STLINK_F_FIX_CLOSE_AP)
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+ else
+ return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
+
+}
+
+static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *buffer)
+{
+ struct stlink_usb_handle_s *h = handle;
+ unsigned int buflen = ALIGN_UP(items, 4) + 4 * items;
+
+ LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items);
+
+ assert(handle != NULL);
+
+ if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
+ return ERROR_COMMAND_NOTFOUND;
+
+ stlink_usb_init_buffer(handle, h->tx_ep, buflen);
+
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_OUT;
+ h_u32_to_le(&h->cmdbuf[2], items);
+
+ return stlink_usb_xfer_noerrcheck(handle, buffer, buflen);
+}
+
+static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer)
+{
+ struct stlink_usb_handle_s *h = handle;
+ unsigned int buflen = 2 * 4 * items;
+
+ LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items);
+
+ assert(handle != NULL);
+
+ if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
+ return ERROR_COMMAND_NOTFOUND;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, buflen);
+
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_IN;
+
+ int res = stlink_usb_xfer_noerrcheck(handle, h->databuf, buflen);
+ if (res != ERROR_OK)
+ return res;
+
+ memcpy(buffer, h->databuf, buflen);
+
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_read_dap_register(void *handle, unsigned short dap_port,
+ unsigned short addr, uint32_t *val)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int retval;
+
+ assert(handle);
+
+ if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
+ return ERROR_COMMAND_NOTFOUND;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_DAP_REG;
+ h_u16_to_le(&h->cmdbuf[2], dap_port);
+ h_u16_to_le(&h->cmdbuf[4], addr);
+
+ retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8);
+ *val = le_to_h_u32(h->databuf + 4);
+ LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, *val);
+ return retval;
+}
+
+/** */
+static int stlink_write_dap_register(void *handle, unsigned short dap_port,
+ unsigned short addr, uint32_t val)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle);
+
+ if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
+ return ERROR_COMMAND_NOTFOUND;
+
+ LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, val);
+ stlink_usb_init_buffer(handle, h->rx_ep, 16);
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG;
+ h_u16_to_le(&h->cmdbuf[2], dap_port);
+ h_u16_to_le(&h->cmdbuf[4], addr);
+ h_u32_to_le(&h->cmdbuf[6], val);
+ return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+}
+
+/** */
+struct hl_layout_api_s stlink_usb_layout_api = {
+ /** */
+ .open = stlink_usb_hl_open,
+ /** */
+ .close = stlink_close,
+ /** */
+ .idcode = stlink_usb_idcode,
+ /** */
+ .state = stlink_usb_state,
+ /** */
+ .reset = stlink_usb_reset,
+ /** */
+ .assert_srst = stlink_usb_assert_srst,
+ /** */
+ .run = stlink_usb_run,
+ /** */
+ .halt = stlink_usb_halt,
+ /** */
+ .step = stlink_usb_step,
+ /** */
+ .read_regs = stlink_usb_read_regs,
+ /** */
+ .read_reg = stlink_usb_read_reg,
+ /** */
+ .write_reg = stlink_usb_write_reg,
+ /** */
+ .read_mem = stlink_usb_read_mem,
+ /** */
+ .write_mem = stlink_usb_write_mem,
+ /** */
+ .write_debug_reg = stlink_usb_write_debug_reg,
+ /** */
+ .override_target = stlink_usb_override_target,
+ /** */
+ .speed = stlink_speed,
+ /** */
+ .config_trace = stlink_config_trace,
+ /** */
+ .poll_trace = stlink_usb_trace_read,
+};
+
+/*****************************************************************************
+ * DAP direct interface
+ */
+
+static struct stlink_usb_handle_s *stlink_dap_handle;
+static struct hl_interface_param_s stlink_dap_param;
+static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1);
+static uint32_t last_csw_default[DP_APSEL_MAX + 1];
+static int stlink_dap_error = ERROR_OK;
+
+/** */
+static int stlink_dap_record_error(int error)
+{
+ if (stlink_dap_error == ERROR_OK)
+ stlink_dap_error = error;
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_get_and_clear_error(void)
+{
+ int retval = stlink_dap_error;
+ stlink_dap_error = ERROR_OK;
+ 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;
+ int retval;
+
+ /* nothing to do on old versions */
+ if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_OK;
+
+ if (apsel > DP_APSEL_MAX)
+ return ERROR_FAIL;
+
+ if (test_bit(apsel, opened_ap))
+ return ERROR_OK;
+
+ retval = stlink_usb_init_access_port(h, apsel);
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_DEBUG("AP %d enabled", apsel);
+ set_bit(apsel, opened_ap);
+ last_csw_default[apsel] = 0;
+ return ERROR_OK;
+}
+
+static int stlink_dap_open_ap(unsigned short apsel)
+{
+ return stlink_usb_open_ap(stlink_dap_handle, apsel);
+}
+
+/** */
+static int stlink_dap_closeall_ap(void)
+{
+ int retval, apsel;
+
+ /* nothing to do on old versions */
+ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT))
+ return ERROR_OK;
+
+ for (apsel = 0; apsel <= DP_APSEL_MAX; apsel++) {
+ if (!test_bit(apsel, opened_ap))
+ continue;
+ retval = stlink_usb_close_access_port(stlink_dap_handle, apsel);
+ if (retval != ERROR_OK)
+ return retval;
+ clear_bit(apsel, opened_ap);
+ }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_reinit_interface(void)
+{
+ int retval;
+
+ /*
+ * On JTAG only, it should be enough to call stlink_usb_reset(). But on
+ * some firmware version it does not work as expected, and there is no
+ * equivalent for SWD.
+ * At least for now, to reset the interface quit from JTAG/SWD mode then
+ * select the mode again.
+ */
+
+ if (!stlink_dap_handle->reconnect_pending) {
+ stlink_dap_handle->reconnect_pending = true;
+ stlink_usb_mode_leave(stlink_dap_handle, stlink_dap_handle->st_mode);
+ }
+
+ retval = stlink_usb_mode_enter(stlink_dap_handle, stlink_dap_handle->st_mode);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stlink_dap_handle->reconnect_pending = false;
+ /* on new FW, calling mode-leave closes all the opened AP; reopen them! */
+ if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)
+ for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++)
+ if (test_bit(apsel, opened_ap)) {
+ clear_bit(apsel, opened_ap);
+ stlink_dap_open_ap(apsel);
+ }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_op_connect(struct adiv5_dap *dap)
+{
+ uint32_t idcode;
+ int retval;
+
+ LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : "");
+
+ /* 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)
+ adapter_assert_reset();
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ }
+ }
+
+ dap->do_reconnect = false;
+ dap_invalidate_cache(dap);
+ for (unsigned int i = 0; i <= DP_APSEL_MAX; i++)
+ last_csw_default[i] = 0;
+
+ retval = dap_dp_init(dap);
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+
+ retval = stlink_usb_idcode(stlink_dap_handle, &idcode);
+ if (retval == ERROR_OK)
+ LOG_INFO("%s %#8.8" PRIx32,
+ (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) ? "JTAG IDCODE" : "SWD DPIDR",
+ idcode);
+ else
+ dap->do_reconnect = true;
+
+ return retval;
+}
+
+/** */
+static int stlink_dap_check_reconnect(struct adiv5_dap *dap)
+{
+ int retval;
+
+ if (!dap->do_reconnect)
+ return ERROR_OK;
+
+ retval = stlink_dap_reinit_interface();
+ if (retval != ERROR_OK)
+ return retval;
+
+ return stlink_dap_op_connect(dap);
+}
+
+/** */
+static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+ /* Ignore the request */
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data)
+{
+ uint32_t dummy;
+ int retval;
+
+ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL))
+ if (reg & 0x000000F0) {
+ LOG_ERROR("Banked DP registers not supported in current STLink FW");
+ return ERROR_COMMAND_NOTFOUND;
+ }
+
+ 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) {
+ /* Quirk required in JTAG. Read RDBUFF to get the data */
+ retval = stlink_read_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, reg, &dummy);
+ if (retval == ERROR_OK)
+ retval = stlink_read_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, DP_RDBUFF, data);
+ } else {
+ retval = stlink_read_dap_register(stlink_dap_handle,
+ STLINK_DEBUG_PORT_ACCESS, reg, data);
+ }
+
+ return retval;
+}
+
+/** */
+static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data)
+{
+ int retval;
+
+ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL))
+ if (reg & 0x000000F0) {
+ LOG_ERROR("Banked DP registers not supported in current STLink FW");
+ return ERROR_COMMAND_NOTFOUND;
+ }
+
+ if (reg == DP_SELECT && (data & DP_SELECT_DPBANK) != 0) {
+ /* ignored if STLINK_F_HAS_DPBANKSEL, not properly managed otherwise */
+ LOG_DEBUG("Ignoring DPBANKSEL while write SELECT");
+ data &= ~DP_SELECT_DPBANK;
+ }
+
+ /* 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 retval;
+}
+
+/** */
+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;
+
+ if (reg != AP_REG_IDR) {
+ retval = stlink_dap_open_ap(ap->ap_num);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ data = data ? data : &dummy;
+ retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg,
+ data);
+ dap->stlink_flush_ap_write = false;
+ return retval;
+}
+
+/** */
+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_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 retval;
+}
+
+/** */
+static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
+{
+ LOG_WARNING("stlink_dap_op_queue_ap_abort()");
+ return ERROR_OK;
+}
+
+#define RW_MISC_CMD_ADDRESS 1
+#define RW_MISC_CMD_WRITE 2
+#define RW_MISC_CMD_READ 3
+#define RW_MISC_CMD_APNUM 5
+
+static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, unsigned int len, unsigned int items)
+{
+ uint8_t buf[2 * 4 * items];
+
+ LOG_DEBUG("Queue: %u commands in %u items", len, items);
+
+ int ap_num = DP_APSEL_INVALID;
+ unsigned int cmd_index = 0;
+ unsigned int val_index = ALIGN_UP(items, 4);
+ for (unsigned int i = 0; i < len; i++) {
+ if (ap_num != q[i].mem_ap.ap->ap_num) {
+ ap_num = q[i].mem_ap.ap->ap_num;
+ buf[cmd_index++] = RW_MISC_CMD_APNUM;
+ h_u32_to_le(&buf[val_index], ap_num);
+ val_index += 4;
+ }
+
+ switch (q[i].cmd) {
+ case CMD_MEM_AP_READ32:
+ buf[cmd_index++] = RW_MISC_CMD_READ;
+ h_u32_to_le(&buf[val_index], q[i].mem_ap.addr);
+ val_index += 4;
+ break;
+ case CMD_MEM_AP_WRITE32:
+ buf[cmd_index++] = RW_MISC_CMD_ADDRESS;
+ h_u32_to_le(&buf[val_index], q[i].mem_ap.addr);
+ val_index += 4;
+ buf[cmd_index++] = RW_MISC_CMD_WRITE;
+ h_u32_to_le(&buf[val_index], q[i].mem_ap.data);
+ val_index += 4;
+ break;
+ default:
+ /* Not supposed to happen */
+ return ERROR_FAIL;
+ }
+ }
+ /* pad after last command */
+ while (!IS_ALIGNED(cmd_index, 4))
+ buf[cmd_index++] = 0;
+
+ int retval = stlink_usb_rw_misc_out(handle, items, buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stlink_usb_rw_misc_in(handle, items, buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ ap_num = DP_APSEL_INVALID;
+ val_index = 0;
+ unsigned int err_index = 4 * items;
+ for (unsigned int i = 0; i < len; i++) {
+ uint32_t errcode = le_to_h_u32(&buf[err_index]);
+ if (errcode != STLINK_DEBUG_ERR_OK) {
+ LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode);
+ return ERROR_FAIL;
+ }
+ if (ap_num != q[i].mem_ap.ap->ap_num) {
+ ap_num = q[i].mem_ap.ap->ap_num;
+ err_index += 4;
+ val_index += 4;
+ errcode = le_to_h_u32(&buf[err_index]);
+ if (errcode != STLINK_DEBUG_ERR_OK) {
+ LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode);
+ return ERROR_FAIL;
+ }
+ }
+
+ if (q[i].cmd == CMD_MEM_AP_READ32) {
+ *q[i].mem_ap.p_data = le_to_h_u32(&buf[val_index]);
+ } else { /* q[i]->cmd == CMD_MEM_AP_WRITE32 */
+ err_index += 4;
+ val_index += 4;
+ errcode = le_to_h_u32(&buf[err_index]);
+ if (errcode != STLINK_DEBUG_ERR_OK) {
+ LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode);
+ return ERROR_FAIL;
+ }
+ }
+ err_index += 4;
+ val_index += 4;
+ }
+
+ 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);
+ if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr)
+ return stlink_usb_write_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+ else
+ 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:
+ if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr)
+ retval = stlink_usb_read_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+ else
+ 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;
+ };
+}
+
+/* TODO: recover these values with cmd STLINK_DEBUG_APIV2_RW_MISC_GET_MAX (0x53) */
+#define STLINK_V2_RW_MISC_SIZE (64)
+#define STLINK_V3_RW_MISC_SIZE (1227)
+
+static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *q, unsigned int len,
+ unsigned int *pkt_items)
+{
+ struct stlink_usb_handle_s *h = handle;
+ unsigned int i, items = 0;
+ int ap_num = DP_APSEL_INVALID;
+ unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE;
+
+ if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
+ return 0;
+ /*
+ * RW_MISC sequence doesn't lock the st-link, so are not safe in shared mode.
+ * Don't use it with TCP backend to prevent any issue in case of sharing.
+ * This further degrades the performance, on top of TCP server overhead.
+ */
+ if (h->backend == &stlink_tcp_backend)
+ return 0;
+
+ for (i = 0; i < len; i++) {
+ if (q[i].cmd != CMD_MEM_AP_READ32 && q[i].cmd != CMD_MEM_AP_WRITE32)
+ break;
+ unsigned int count = 1;
+ if (ap_num != q[i].mem_ap.ap->ap_num) {
+ count++;
+ ap_num = q[i].mem_ap.ap->ap_num;
+ }
+ if (q[i].cmd == CMD_MEM_AP_WRITE32)
+ count++;
+ if (items + count > misc_max_items)
+ break;
+ items += count;
+ }
+
+ *pkt_items = items;
+
+ return i;
+}
+
+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;
+
+ /* check for no address increment, 32 bits only */
+ if (len > 1 && incr == 4 && q[0].mem_ap.addr == q[1].mem_ap.addr)
+ incr = 0;
+
+ 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, misc_items = 0;
+ int retval;
+
+ unsigned int count_misc = stlink_usb_count_misc_rw_queue(handle, q, len, &misc_items);
+ unsigned int count_buf = stlink_usb_count_buf_rw_queue(q, len);
+
+ if (count_misc > count_buf) {
+ count = count_misc;
+ retval = stlink_usb_misc_rw_segment(handle, q, count, misc_items);
+ } else {
+ count = count_buf;
+ retval = stlink_usb_buf_rw_segment(handle, q, count_buf);
+ }
+ 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_run_finalize(struct adiv5_dap *dap)
+{
+ uint32_t ctrlstat, pwrmask;
+ int retval, saved_retval;
+
+ /* Here no LOG_DEBUG. This is called continuously! */
+
+ /*
+ * ST-Link returns immediately after a DAP write, without waiting for it
+ * to complete.
+ * Run a dummy read to DP_RDBUFF, as suggested in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16363.html
+ */
+ if (dap->stlink_flush_ap_write) {
+ dap->stlink_flush_ap_write = false;
+ 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_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect");
+ dap->do_reconnect = true;
+ return retval;
+ }
+
+ if (ctrlstat & SSTICKYERR) {
+ if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG)
+ retval = stlink_dap_dp_write(dap, DP_CTRL_STAT,
+ ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR));
+ else
+ retval = stlink_dap_dp_write(dap, DP_ABORT, STKERRCLR);
+ if (retval != ERROR_OK) {
+ dap->do_reconnect = true;
+ return retval;
+ }
+ }
+
+ /* check for power lost */
+ pwrmask = dap->dp_ctrl_stat & (CDBGPWRUPREQ | CSYSPWRUPREQ);
+ if ((ctrlstat & pwrmask) != pwrmask)
+ dap->do_reconnect = true;
+
+ 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)
+{
+ int retval;
+
+ retval = stlink_dap_closeall_ap();
+ if (retval != ERROR_OK)
+ 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];
+
+ /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_RD_NO_INC
+ * and STLINK_F_HAS_RW_MISC */
+ 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 it didn't changed ap->csw_default */
+ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW &&
+ !prev_q->ap_w.changes_csw_default) {
+ 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];
+
+ /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_WR_NO_INC
+ * and STLINK_F_HAS_RW_MISC */
+ 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 it didn't changed ap->csw_default */
+ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW &&
+ !prev_q->ap_w.changes_csw_default) {
+ 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 (reg == MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap->ap_num]) {
+ q->ap_w.changes_csw_default = true;
+ last_csw_default[ap->ap_num] = ap->csw_default;
+ } else {
+ q->ap_w.changes_csw_default = false;
+ }
+ }
+
+ 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);
+}
+
+static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size,
+ uint32_t count, uint8_t *buffer)
+{
+ int retval;
+ uint32_t bytes_remaining;
+
+ LOG_DEBUG_IO("read at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count);
+ count *= size;
+
+ while (count) {
+ bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count;
+ retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += bytes_remaining;
+ addr += bytes_remaining;
+ count -= bytes_remaining;
+ }
+
+ return ERROR_OK;
+}
+
+static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size,
+ uint32_t count, const uint8_t *buffer)
+{
+ int retval;
+ uint32_t bytes_remaining;
+
+ LOG_DEBUG_IO("write at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count);
+ count *= size;
+
+ while (count) {
+ bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count;
+ retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += bytes_remaining;
+ addr += bytes_remaining;
+ count -= bytes_remaining;
+ }
+
+ return ERROR_OK;
+}
+
+static int stlink_swim_op_reconnect(void)
+{
+ int retval;
+
+ retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return stlink_swim_resync(stlink_dap_handle);
+}
+
+static int stlink_dap_config_trace(bool enabled,
+ enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+ unsigned int *trace_freq, unsigned int traceclkin_freq,
+ uint16_t *prescaler)
+{
+ return stlink_config_trace(stlink_dap_handle, enabled, pin_protocol,
+ port_size, trace_freq, traceclkin_freq,
+ prescaler);
+}
+
+static int stlink_dap_trace_read(uint8_t *buf, size_t *size)
+{
+ return stlink_usb_trace_read(stlink_dap_handle, buf, size);
+}
+
+/** */
+COMMAND_HANDLER(stlink_dap_vid_pid)
+{
+ unsigned int i, max_usb_ids = HLA_MAX_USB_IDS;
+
+ if (CMD_ARGC > max_usb_ids * 2) {
+ LOG_WARNING("ignoring extra IDs in vid_pid "
+ "(maximum is %d pairs)", max_usb_ids);
+ CMD_ARGC = max_usb_ids * 2;
+ }
+ if (CMD_ARGC < 2 || (CMD_ARGC & 1)) {
+ LOG_WARNING("incomplete vid_pid configuration directive");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ for (i = 0; i < CMD_ARGC; i += 2) {
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]);
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]);
+ }
+
+ /* null termination */
+ stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0;
+
+ return ERROR_OK;
+}
+
+/** */
+COMMAND_HANDLER(stlink_dap_backend_command)
+{
+ /* default values */
+ bool use_stlink_tcp = false;
+ uint16_t stlink_tcp_port = 7184;
+
+ if (CMD_ARGC == 0 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ else if (strcmp(CMD_ARGV[0], "usb") == 0) {
+ if (CMD_ARGC > 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ /* else use_stlink_tcp = false (already the case ) */
+ } else if (strcmp(CMD_ARGV[0], "tcp") == 0) {
+ use_stlink_tcp = true;
+ if (CMD_ARGC == 2)
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port);
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ stlink_dap_param.use_stlink_tcp = use_stlink_tcp;
+ stlink_dap_param.stlink_tcp_port = stlink_tcp_port;
+
+ return ERROR_OK;
+}
+
+#define BYTES_PER_LINE 16
+COMMAND_HANDLER(stlink_dap_cmd_command)
+{
+ unsigned int rx_n, tx_n;
+ struct stlink_usb_handle_s *h = stlink_dap_handle;
+
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], rx_n);
+ tx_n = CMD_ARGC - 1;
+ if (tx_n > STLINK_SG_SIZE || rx_n > STLINK_DATA_SIZE) {
+ LOG_ERROR("max %x byte sent and %d received", STLINK_SG_SIZE, STLINK_DATA_SIZE);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ stlink_usb_init_buffer(h, h->rx_ep, rx_n);
+
+ for (unsigned int i = 0; i < tx_n; i++) {
+ uint8_t byte;
+ COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 1], byte);
+ h->cmdbuf[h->cmdidx++] = byte;
+ }
+
+ int retval = stlink_usb_xfer_noerrcheck(h, h->databuf, rx_n);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Error %d", retval);
+ return retval;
+ }
+
+ for (unsigned int i = 0; i < rx_n; i++)
+ command_print_sameline(CMD, "0x%02x%c", h->databuf[i],
+ ((i == (rx_n - 1)) || ((i % BYTES_PER_LINE) == (BYTES_PER_LINE - 1))) ? '\n' : ' ');
+
+ return ERROR_OK;
+}
+
+/** */
+static const struct command_registration stlink_dap_subcommand_handlers[] = {
+ {
+ .name = "vid_pid",
+ .handler = stlink_dap_vid_pid,
+ .mode = COMMAND_CONFIG,
+ .help = "USB VID and PID of the adapter",
+ .usage = "(vid pid)+",
+ },
+ {
+ .name = "backend",
+ .handler = &stlink_dap_backend_command,
+ .mode = COMMAND_CONFIG,
+ .help = "select which ST-Link backend to use",
+ .usage = "usb | tcp [port]",
+ },
+ {
+ .name = "cmd",
+ .handler = stlink_dap_cmd_command,
+ .mode = COMMAND_EXEC,
+ .help = "send arbitrary command",
+ .usage = "rx_n (tx_byte)+",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+/** */
+static const struct command_registration stlink_dap_command_handlers[] = {
+ {
+ .name = "st-link",
+ .mode = COMMAND_ANY,
+ .help = "perform st-link management",
+ .chain = stlink_dap_subcommand_handlers,
+ .usage = "",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+/** */
+static int stlink_dap_init(void)
+{
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+ enum stlink_mode mode;
+ int retval;
+
+ LOG_DEBUG("stlink_dap_init()");
+
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING)
+ stlink_dap_param.connect_under_reset = true;
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ }
+
+ if (transport_is_dapdirect_swd())
+ mode = STLINK_MODE_DEBUG_SWD;
+ else if (transport_is_dapdirect_jtag())
+ mode = STLINK_MODE_DEBUG_JTAG;
+ else if (transport_is_swim())
+ mode = STLINK_MODE_DEBUG_SWIM;
+ else {
+ LOG_ERROR("Unsupported transport");
+ return ERROR_FAIL;
+ }
+
+ retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((mode != STLINK_MODE_DEBUG_SWIM) &&
+ !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) {
+ LOG_ERROR("ST-Link version does not support DAP direct transport");
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_quit(void)
+{
+ LOG_DEBUG("stlink_dap_quit()");
+
+ return stlink_close(stlink_dap_handle);
+}
+
+/** */
+static int stlink_dap_reset(int req_trst, int req_srst)
+{
+ LOG_DEBUG("stlink_dap_reset(%d)", req_srst);
+ return stlink_usb_assert_srst(stlink_dap_handle,
+ req_srst ? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW
+ : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH);
+}
+
+/** */
+static int stlink_dap_speed(int speed)
+{
+ if (speed == 0) {
+ LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+ }
+
+ stlink_dap_param.initial_interface_speed = speed;
+ stlink_speed(stlink_dap_handle, speed, false);
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_khz(int khz, int *jtag_speed)
+{
+ if (khz == 0) {
+ LOG_ERROR("RCLK not supported");
+ return ERROR_FAIL;
+ }
+
+ *jtag_speed = stlink_speed(stlink_dap_handle, khz, true);
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_speed_div(int speed, int *khz)
+{
+ *khz = speed;
+ return ERROR_OK;
+}
+
+static const struct dap_ops stlink_dap_ops = {
+ .connect = stlink_dap_op_connect,
+ .send_sequence = stlink_dap_op_send_sequence,
+ .queue_dp_read = stlink_dap_op_queue_dp_read,
+ .queue_dp_write = stlink_dap_op_queue_dp_write,
+ .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_queue_run,
+ .sync = NULL, /* optional */
+ .quit = stlink_dap_op_quit, /* optional */
+};
+
+static const struct swim_driver stlink_swim_ops = {
+ .srst = stlink_swim_op_srst,
+ .read_mem = stlink_swim_op_read_mem,
+ .write_mem = stlink_swim_op_write_mem,
+ .reconnect = stlink_swim_op_reconnect,
+};
+
+static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL };
+
+struct adapter_driver stlink_dap_adapter_driver = {
+ .name = "st-link",
+ .transports = stlink_dap_transport,
+ .commands = stlink_dap_command_handlers,
+
+ .init = stlink_dap_init,
+ .quit = stlink_dap_quit,
+ .reset = stlink_dap_reset,
+ .speed = stlink_dap_speed,
+ .khz = stlink_dap_khz,
+ .speed_div = stlink_dap_speed_div,
+ .config_trace = stlink_dap_config_trace,
+ .poll_trace = stlink_dap_trace_read,
+
+ .dap_jtag_ops = &stlink_dap_ops,
+ .dap_swd_ops = &stlink_dap_ops,
+ .swim_ops = &stlink_swim_ops,