flash/nor/at91samd: Use 32-bit register writes for ST-Link compat
[fw/openocd] / src / jtag / drivers / stlink_usb.c
index 325848f8616df22c9a259625a7b4fad212786eac..5b051c1ff9dff034b3e71f9a2d1a083155bdbdff 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2020 by Tarek Bochkati                                  *
  *   Tarek Bochkati <tarek.bouchkati@gmail.com>                            *
  *   spen@spen-soft.co.uk                                                  *
  *                                                                         *
  *   This code is based on https://github.com/texane/stlink                *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   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, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -71,8 +60,8 @@
 #define ENDPOINT_IN  0x80
 #define ENDPOINT_OUT 0x00
 
-#define STLINK_WRITE_TIMEOUT 1000
-#define STLINK_READ_TIMEOUT 1000
+#define STLINK_WRITE_TIMEOUT  (LIBUSB_TIMEOUT_MS)
+#define STLINK_READ_TIMEOUT   (LIBUSB_TIMEOUT_MS)
 
 #define STLINK_RX_EP          (1|ENDPOINT_IN)
 #define STLINK_TX_EP          (2|ENDPOINT_OUT)
@@ -504,6 +493,8 @@ static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, i
 #define STLINK_TCP_SS_CMD_NOT_AVAILABLE      0x00001053
 #define STLINK_TCP_SS_TCP_ERROR              0x00002001
 #define STLINK_TCP_SS_TCP_CANT_CONNECT       0x00002002
+#define STLINK_TCP_SS_TCP_CLOSE_ERROR        0x00002003
+#define STLINK_TCP_SS_TCP_BUSY               0x00002004
 #define STLINK_TCP_SS_WIN32_ERROR            0x00010000
 
 /*
@@ -971,6 +962,11 @@ static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool
        if (check_tcp_status) {
                uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf);
                if (tcp_ss != STLINK_TCP_SS_OK) {
+                       if (tcp_ss == STLINK_TCP_SS_TCP_BUSY) {
+                               LOG_DEBUG("TCP busy");
+                               return ERROR_WAIT;
+                       }
+
                        LOG_ERROR("TCP error status 0x%X", tcp_ss);
                        return ERROR_FAIL;
                }
@@ -4145,7 +4141,7 @@ static int stlink_dap_reinit_interface(void)
        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++)
+               for (unsigned int apsel = 0; apsel <= DP_APSEL_MAX; apsel++)
                        if (test_bit(apsel, opened_ap)) {
                                clear_bit(apsel, opened_ap);
                                stlink_dap_open_ap(apsel);
@@ -4279,7 +4275,15 @@ static int stlink_dap_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *d
        uint32_t dummy;
        int retval;
 
-       if (reg != AP_REG_IDR) {
+       if (is_adiv6(dap)) {
+               static bool error_flagged;
+               if (!error_flagged)
+                       LOG_ERROR("ADIv6 dap not supported by stlink dap-direct mode");
+               error_flagged = true;
+               return ERROR_FAIL;
+       }
+
+       if (reg != ADIV5_AP_REG_IDR) {
                retval = stlink_dap_open_ap(ap->ap_num);
                if (retval != ERROR_OK)
                        return retval;
@@ -4297,6 +4301,14 @@ static int stlink_dap_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t d
        struct adiv5_dap *dap = ap->dap;
        int retval;
 
+       if (is_adiv6(dap)) {
+               static bool error_flagged;
+               if (!error_flagged)
+                       LOG_ERROR("ADIv6 dap not supported by stlink dap-direct mode");
+               error_flagged = true;
+               return ERROR_FAIL;
+       }
+
        retval = stlink_dap_open_ap(ap->ap_num);
        if (retval != ERROR_OK)
                return retval;
@@ -4325,7 +4337,7 @@ static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, u
 
        LOG_DEBUG("Queue: %u commands in %u items", len, items);
 
-       int ap_num = DP_APSEL_INVALID;
+       uint32_t 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++) {
@@ -4474,7 +4486,7 @@ static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *
 {
        struct stlink_usb_handle_s *h = handle;
        unsigned int i, items = 0;
-       int ap_num = DP_APSEL_INVALID;
+       uint32_t 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))
@@ -4584,7 +4596,7 @@ static void stlink_dap_run_internal(struct adiv5_dap *dap)
                        break;
                case CMD_AP_WRITE:
                        /* ignore increment packed, not supported */
-                       if (q->ap_w.reg == MEM_AP_REG_CSW)
+                       if (q->ap_w.reg == ADIV5_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;
@@ -4729,18 +4741,18 @@ static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg,
        /* 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)) {
+                       (reg == ADIV5_MEM_AP_REG_DRW || reg == ADIV5_MEM_AP_REG_BD0 || reg == ADIV5_MEM_AP_REG_BD1 ||
+                        reg == ADIV5_MEM_AP_REG_BD2 || reg == ADIV5_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) {
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_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 &&
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_CSW &&
                                !prev_q->ap_w.changes_csw_default) {
                        stlink_dap_handle->queue_index = i;
                        q = prev_q;
@@ -4762,7 +4774,7 @@ static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg,
                        return ERROR_FAIL;
                }
 
-               q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c));
+               q->mem_ap.addr = (reg == ADIV5_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;
@@ -4795,18 +4807,18 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg,
        /* 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)) {
+                       (reg == ADIV5_MEM_AP_REG_DRW || reg == ADIV5_MEM_AP_REG_BD0 || reg == ADIV5_MEM_AP_REG_BD1 ||
+                        reg == ADIV5_MEM_AP_REG_BD2 || reg == ADIV5_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) {
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_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 &&
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_CSW &&
                                !prev_q->ap_w.changes_csw_default) {
                        stlink_dap_handle->queue_index = i;
                        q = prev_q;
@@ -4828,7 +4840,7 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg,
                        return ERROR_FAIL;
                }
 
-               q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c));
+               q->mem_ap.addr = (reg == ADIV5_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;
@@ -4841,9 +4853,10 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg,
                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]) {
+               uint8_t ap_num = ap->ap_num;
+               if (reg == ADIV5_MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap_num]) {
                        q->ap_w.changes_csw_default = true;
-                       last_csw_default[ap->ap_num] = ap->csw_default;
+                       last_csw_default[ap_num] = ap->csw_default;
                } else {
                        q->ap_w.changes_csw_default = false;
                }