Make NetBSD a recognized system
[fw/openocd] / src / jtag / drivers / stlink_usb.c
index e373a27a19e7d5a5d6777ec01f92a7ab2ed5b01c..4382538d2d339a43a57b20bfedc775bdc4d022ab 100644 (file)
@@ -2,6 +2,9 @@
  *   Copyright (C) 2011-2012 by Mathias Kuester                            *
  *   Mathias Kuester <kesmtp@freenet.de>                                   *
  *                                                                         *
+ *   Copyright (C) 2012 by Spencer Oliver                                  *
+ *   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  *
 #include <jtag/stlink/stlink_interface.h>
 #include <target/target.h>
 
+#include <target/cortex_m.h>
+
 #include "libusb_common.h"
 
-#define ENDPOINT_IN    0x80
-#define ENDPOINT_OUT   0x00
+#define ENDPOINT_IN  0x80
+#define ENDPOINT_OUT 0x00
 
-#define STLINK_NULL_EP         0
-#define STLINK_RX_EP           (1|ENDPOINT_IN)
-#define STLINK_TX_EP           (2|ENDPOINT_OUT)
-#define STLINK_SG_SIZE         (31)
-#define STLINK_DATA_SIZE       (4*128)
-#define STLINK_CMD_SIZE_V2     (16)
-#define STLINK_CMD_SIZE_V1     (10)
+#define STLINK_NULL_EP     0
+#define STLINK_RX_EP       (1|ENDPOINT_IN)
+#define STLINK_TX_EP       (2|ENDPOINT_OUT)
+#define STLINK_SG_SIZE     (31)
+#define STLINK_DATA_SIZE   (4*128)
+#define STLINK_CMD_SIZE_V2 (16)
+#define STLINK_CMD_SIZE_V1 (10)
 
 enum stlink_jtag_api_version {
-       STLINK_JTAG_API_V1 = 0,
+       STLINK_JTAG_API_V1 = 1,
        STLINK_JTAG_API_V2,
 };
 
@@ -88,68 +93,73 @@ struct stlink_usb_handle_s {
        enum stlink_jtag_api_version jtag_api;
 };
 
-#define STLINK_DEBUG_ERR_OK                    0x80
-#define STLINK_DEBUG_ERR_FAULT                 0x81
-#define STLINK_CORE_RUNNING                    0x80
-#define STLINK_CORE_HALTED                     0x81
-#define STLINK_CORE_STAT_UNKNOWN               -1
-
-#define STLINK_GET_VERSION                     0xF1
-#define STLINK_DEBUG_COMMAND                   0xF2
-#define STLINK_DFU_COMMAND                     0xF3
-#define STLINK_SWIM_COMMAND                    0xF4
-#define STLINK_GET_CURRENT_MODE                        0xF5
-
-#define STLINK_DEV_DFU_MODE                    0x00
-#define STLINK_DEV_MASS_MODE                   0x01
-#define STLINK_DEV_DEBUG_MODE                  0x02
-#define STLINK_DEV_SWIM_MODE                   0x03
-#define STLINK_DEV_BOOTLOADER_MODE             0x04
-#define STLINK_DEV_UNKNOWN_MODE                        -1
-
-#define STLINK_DFU_EXIT                                0x07
-
-#define STLINK_SWIM_ENTER                      0x00
-#define STLINK_SWIM_EXIT                       0x01
-
-#define STLINK_DEBUG_ENTER_JTAG                        0x00
-#define STLINK_DEBUG_GETSTATUS                 0x01
-#define STLINK_DEBUG_FORCEDEBUG                        0x02
-#define STLINK_DEBUG_APIV1_RESETSYS            0x03
-#define STLINK_DEBUG_APIV1_READALLREGS         0x04
-#define STLINK_DEBUG_APIV1_READREG             0x05
-#define STLINK_DEBUG_APIV1_WRITEREG            0x06
-#define STLINK_DEBUG_READMEM_32BIT             0x07
-#define STLINK_DEBUG_WRITEMEM_32BIT            0x08
-#define STLINK_DEBUG_RUNCORE                   0x09
-#define STLINK_DEBUG_STEPCORE                  0x0a
-#define STLINK_DEBUG_APIV1_SETFP               0x0b
-#define STLINK_DEBUG_READMEM_8BIT              0x0c
-#define STLINK_DEBUG_WRITEMEM_8BIT             0x0d
-#define STLINK_DEBUG_APIV1_CLEARFP             0x0e
-#define STLINK_DEBUG_APIV1_WRITEDEBUGREG       0x0f
-#define STLINK_DEBUG_APIV1_SETWATCHPOINT       0x10
-
-#define STLINK_DEBUG_ENTER_JTAG                        0x00
-#define STLINK_DEBUG_ENTER_SWD                 0xa3
-
-#define STLINK_DEBUG_APIV1_ENTER               0x20
-#define STLINK_DEBUG_EXIT                      0x21
-#define STLINK_DEBUG_READCOREID                        0x22
-
-#define STLINK_DEBUG_APIV2_ENTER               0x30
-#define STLINK_DEBUG_APIV2_READ_IDCODES                0x31
-#define STLINK_DEBUG_APIV2_RESETSYS            0x32
-#define STLINK_DEBUG_APIV2_READREG             0x33
-#define STLINK_DEBUG_APIV2_WRITEREG            0x34
-
-#define STLINK_DEBUG_APIV2_READALLREGS         0x3A
-
-#define STLINK_DEBUG_APIV2_DRIVE_NRST          0x3C
-
-#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW      0x00
-#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH     0x01
-#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE    0x02
+#define STLINK_DEBUG_ERR_OK            0x80
+#define STLINK_DEBUG_ERR_FAULT         0x81
+#define STLINK_SWD_AP_WAIT             0x10
+#define STLINK_SWD_DP_WAIT             0x14
+
+#define STLINK_CORE_RUNNING            0x80
+#define STLINK_CORE_HALTED             0x81
+#define STLINK_CORE_STAT_UNKNOWN       -1
+
+#define STLINK_GET_VERSION             0xF1
+#define STLINK_DEBUG_COMMAND           0xF2
+#define STLINK_DFU_COMMAND             0xF3
+#define STLINK_SWIM_COMMAND            0xF4
+#define STLINK_GET_CURRENT_MODE        0xF5
+
+#define STLINK_DEV_DFU_MODE            0x00
+#define STLINK_DEV_MASS_MODE           0x01
+#define STLINK_DEV_DEBUG_MODE          0x02
+#define STLINK_DEV_SWIM_MODE           0x03
+#define STLINK_DEV_BOOTLOADER_MODE     0x04
+#define STLINK_DEV_UNKNOWN_MODE        -1
+
+#define STLINK_DFU_EXIT                0x07
+
+#define STLINK_SWIM_ENTER              0x00
+#define STLINK_SWIM_EXIT               0x01
+
+#define STLINK_DEBUG_ENTER_JTAG            0x00
+#define STLINK_DEBUG_GETSTATUS             0x01
+#define STLINK_DEBUG_FORCEDEBUG            0x02
+#define STLINK_DEBUG_APIV1_RESETSYS        0x03
+#define STLINK_DEBUG_APIV1_READALLREGS     0x04
+#define STLINK_DEBUG_APIV1_READREG         0x05
+#define STLINK_DEBUG_APIV1_WRITEREG        0x06
+#define STLINK_DEBUG_READMEM_32BIT         0x07
+#define STLINK_DEBUG_WRITEMEM_32BIT        0x08
+#define STLINK_DEBUG_RUNCORE               0x09
+#define STLINK_DEBUG_STEPCORE              0x0a
+#define STLINK_DEBUG_APIV1_SETFP           0x0b
+#define STLINK_DEBUG_READMEM_8BIT          0x0c
+#define STLINK_DEBUG_WRITEMEM_8BIT         0x0d
+#define STLINK_DEBUG_APIV1_CLEARFP         0x0e
+#define STLINK_DEBUG_APIV1_WRITEDEBUGREG   0x0f
+#define STLINK_DEBUG_APIV1_SETWATCHPOINT   0x10
+
+#define STLINK_DEBUG_ENTER_JTAG            0x00
+#define STLINK_DEBUG_ENTER_SWD             0xa3
+
+#define STLINK_DEBUG_APIV1_ENTER           0x20
+#define STLINK_DEBUG_EXIT                  0x21
+#define STLINK_DEBUG_READCOREID            0x22
+
+#define STLINK_DEBUG_APIV2_ENTER           0x30
+#define STLINK_DEBUG_APIV2_READ_IDCODES    0x31
+#define STLINK_DEBUG_APIV2_RESETSYS        0x32
+#define STLINK_DEBUG_APIV2_READREG         0x33
+#define STLINK_DEBUG_APIV2_WRITEREG        0x34
+#define STLINK_DEBUG_APIV2_WRITEDEBUGREG   0x35
+#define STLINK_DEBUG_APIV2_READDEBUGREG    0x36
+
+#define STLINK_DEBUG_APIV2_READALLREGS     0x3A
+#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B
+#define STLINK_DEBUG_APIV2_DRIVE_NRST      0x3C
+
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW   0x00
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH  0x01
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02
 
 /** */
 enum stlink_mode {
@@ -161,8 +171,8 @@ enum stlink_mode {
        STLINK_MODE_DEBUG_SWIM
 };
 
-#define REQUEST_SENSE          0x03
-#define REQUEST_SENSE_LENGTH   18
+#define REQUEST_SENSE        0x03
+#define REQUEST_SENSE_LENGTH 18
 
 static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
 
@@ -396,10 +406,9 @@ static int stlink_usb_version(void *handle)
        h->pid = buf_get_u32(h->databuf, 32, 16);
 
        /* set the supported jtag api version
-        * V1 doesn't support API V2 at all
-        * V2 support API V2 since JTAG V13
+        * API V2 is supported since JTAG V11
         */
-       if ((h->version.stlink == 2) && (h->version.jtag > 12))
+       if (h->version.jtag >= 11)
                h->version.jtag_api_max = STLINK_JTAG_API_V2;
        else
                h->version.jtag_api_max = STLINK_JTAG_API_V1;
@@ -649,6 +658,78 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode)
        return ERROR_OK;
 }
 
+static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *val)
+{
+       struct stlink_usb_handle_s *h;
+       int res;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 8);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READDEBUGREG;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+
+       res = stlink_usb_xfer(handle, h->databuf, 8);
+
+       if (res != ERROR_OK)
+               return res;
+
+       *val = le_to_h_u32(h->databuf + 4);
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
+{
+       int res;
+       struct stlink_usb_handle_s *h;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEDEBUGREG;
+       else
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEDEBUGREG;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, val);
+       h->cmdidx += 4;
+
+       res = stlink_usb_xfer(handle, h->databuf, 2);
+
+       if (res != ERROR_OK)
+               return res;
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static enum target_state stlink_usb_v2_get_status(void *handle)
+{
+       int result;
+       uint32_t status;
+
+       result = stlink_usb_v2_read_debug_reg(handle, DCB_DHCSR, &status);
+       if  (result != ERROR_OK)
+               return TARGET_UNKNOWN;
+
+       if (status & S_HALT)
+               return TARGET_HALTED;
+       else if (status & S_RESET_ST)
+               return TARGET_RESET;
+
+       return TARGET_RUNNING;
+}
+
 /** */
 static enum target_state stlink_usb_state(void *handle)
 {
@@ -660,7 +741,7 @@ static enum target_state stlink_usb_state(void *handle)
        h = (struct stlink_usb_handle_s *)handle;
 
        if (h->jtag_api == STLINK_JTAG_API_V2)
-               return TARGET_UNKNOWN;
+               return stlink_usb_v2_get_status(handle);
 
        stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
@@ -706,6 +787,36 @@ static int stlink_usb_reset(void *handle)
 
        LOG_DEBUG("RESET: 0x%08X", h->databuf[0]);
 
+       /* the following is not a error under swd (using hardware srst), so return success */
+       if (h->databuf[0] == STLINK_SWD_AP_WAIT || h->databuf[0] == STLINK_SWD_DP_WAIT)
+               return ERROR_OK;
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static int stlink_usb_assert_srst(void *handle, int srst)
+{
+       int res;
+       struct stlink_usb_handle_s *h;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               return ERROR_COMMAND_NOTFOUND;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_DRIVE_NRST;
+       h->cmdbuf[h->cmdidx++] = srst;
+
+       res = stlink_usb_xfer(handle, h->databuf, 2);
+
+       if (res != ERROR_OK)
+               return res;
+
        return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
 }
 
@@ -720,7 +831,7 @@ static int stlink_usb_run(void *handle)
        h = (struct stlink_usb_handle_s *)handle;
 
        if (h->jtag_api == STLINK_JTAG_API_V2)
-               return ERROR_FAIL;
+               return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
 
        stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
@@ -746,7 +857,7 @@ static int stlink_usb_halt(void *handle)
        h = (struct stlink_usb_handle_s *)handle;
 
        if (h->jtag_api == STLINK_JTAG_API_V2)
-               return ERROR_FAIL;
+               return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
 
        stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
@@ -771,8 +882,13 @@ static int stlink_usb_step(void *handle)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       if (h->jtag_api == STLINK_JTAG_API_V2)
-               return ERROR_FAIL;
+       if (h->jtag_api == STLINK_JTAG_API_V2) {
+               /* TODO: this emulates the v1 api, it should really use a similar auto mask isr
+                * that the cortex-m3 currently does. */
+               stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_MASKINTS|C_DEBUGEN);
+               stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_STEP|C_MASKINTS|C_DEBUGEN);
+               return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
+       }
 
        stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
@@ -823,7 +939,7 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle, STLINK_RX_EP, 4);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
 
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        if (h->jtag_api == STLINK_JTAG_API_V1)
@@ -832,12 +948,17 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG;
        h->cmdbuf[h->cmdidx++] = num;
 
-       res = stlink_usb_xfer(handle, h->databuf, 4);
+       res = stlink_usb_xfer(handle, h->databuf, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
 
        if (res != ERROR_OK)
                return res;
 
-       *val = le_to_h_u32(h->databuf);
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               *val = le_to_h_u32(h->databuf);
+       else {
+               *val = le_to_h_u32(h->databuf + 4);
+               return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+       }
 
        return ERROR_OK;
 }
@@ -871,6 +992,31 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
        return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
 }
 
+static int stlink_usb_get_rw_status(void *handle)
+{
+       int res;
+       struct stlink_usb_handle_s *h;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               return ERROR_OK;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS;
+
+       res = stlink_usb_xfer(handle, h->databuf, 2);
+
+       if (res != ERROR_OK)
+               return res;
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : res;
+}
+
 /** */
 static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
                          uint8_t *buffer)
@@ -903,7 +1049,7 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
 
        memcpy(buffer, h->databuf, len);
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
@@ -931,7 +1077,7 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
@@ -963,7 +1109,7 @@ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
 
        memcpy(buffer, h->databuf, len);
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
@@ -993,7 +1139,7 @@ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
@@ -1001,6 +1147,7 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
 {
        int err;
        struct stlink_usb_handle_s *h;
+       enum stlink_jtag_api_version api;
 
        LOG_DEBUG("stlink_usb_open");
 
@@ -1082,8 +1229,17 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
                return err;
        }
 
-       /* set the used jtag api */
-       h->jtag_api = STLINK_JTAG_API_V1;
+       api = h->version.jtag_api_max;
+
+       /* check that user has not requested certain api version
+        * and if they have check it is supported */
+       if ((param->api != 0) && (param->api <= h->version.jtag_api_max)) {
+               api = param->api;
+               LOG_INFO("using stlink api v%d", api);
+       }
+
+       /* set the used jtag api, this will default to the newest supported version */
+       h->jtag_api = api;
 
        /* initialize the debug hardware */
        err = stlink_usb_init_mode(h);
@@ -1119,6 +1275,8 @@ struct stlink_layout_api_s stlink_usb_layout_api = {
        /** */
        .reset = stlink_usb_reset,
        /** */
+       .assert_srst = stlink_usb_assert_srst,
+       /** */
        .run = stlink_usb_run,
        /** */
        .halt = stlink_usb_halt,
@@ -1138,4 +1296,6 @@ struct stlink_layout_api_s stlink_usb_layout_api = {
        .read_mem32 = stlink_usb_read_mem32,
        /** */
        .write_mem32 = stlink_usb_write_mem32,
+       /** */
+       .write_debug_reg = stlink_usb_write_debug_reg
 };