jlink: fix typo
[fw/openocd] / src / jtag / drivers / jlink.c
index 33b15d29525b28cb352ddd89d8dcb48748644eab..8b57ffca234385fb566ef5fdebeba2e214e35efb 100644 (file)
@@ -21,7 +21,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -29,6 +29,7 @@
 #endif
 
 #include <jtag/interface.h>
+#include <jtag/swd.h>
 #include <jtag/commands.h>
 #include "libusb_common.h"
 
  * pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address)
  */
 
-#define VID 0x1366, 0x1366, 0x1366, 0x1366
-#define PID 0x0101, 0x0102, 0x0103, 0x0104
+#define JLINK_OB_PID  0x0105
 
 #define JLINK_WRITE_ENDPOINT   0x02
 #define JLINK_READ_ENDPOINT            0x81
 
+#define JLINK_OB_WRITE_ENDPOINT        0x06
+#define JLINK_OB_READ_ENDPOINT 0x85
+
 static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT;
 static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT;
 static unsigned int jlink_hw_jtag_version = 2;
@@ -64,14 +67,12 @@ static unsigned int jlink_hw_jtag_version = 2;
 /*#define JLINK_TAP_BUFFER_SIZE 256*/
 /*#define JLINK_TAP_BUFFER_SIZE 384*/
 
-#define JLINK_IN_BUFFER_SIZE                   2048
+#define JLINK_IN_BUFFER_SIZE                   (2048 + 1)
 #define JLINK_OUT_BUFFER_SIZE                  (2*2048 + 4)
-#define JLINK_EMU_RESULT_BUFFER_SIZE   64
 
 /* Global USB buffers */
 static uint8_t usb_in_buffer[JLINK_IN_BUFFER_SIZE];
 static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE];
-static uint8_t usb_emu_result_buffer[JLINK_EMU_RESULT_BUFFER_SIZE];
 
 /* Constants for JLink command */
 #define EMU_CMD_VERSION                        0x01
@@ -201,6 +202,11 @@ static char *jlink_hw_type_str[] = {
        "J-Link Pro",
 };
 
+#define JLINK_TIF_JTAG         0
+#define JLINK_TIF_SWD          1
+#define JLINK_SWD_DIR_IN       0
+#define JLINK_SWD_DIR_OUT      1
+
 /* Queue command functions */
 static void jlink_end_state(tap_state_t state);
 static void jlink_state_move(void);
@@ -211,6 +217,9 @@ static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
 static void jlink_reset(int trst, int srst);
 static void jlink_simple_command(uint8_t command);
 static int jlink_get_status(void);
+static int jlink_swd_run_queue(struct adiv5_dap *dap);
+static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data);
+static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
 
 /* J-Link tap buffer functions */
 static void jlink_tap_init(void);
@@ -231,7 +240,6 @@ static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length)
 static int jlink_usb_io(struct jlink *jlink, int out_length, int in_length);
 static int jlink_usb_write(struct jlink *jlink, int out_length);
 static int jlink_usb_read(struct jlink *jlink, int expected_size);
-static int jlink_usb_read_emu_result(struct jlink *jlink);
 
 /* helper functions */
 static int jlink_get_version_info(void);
@@ -249,12 +257,15 @@ static enum tap_state jlink_last_state = TAP_RESET;
 static struct jlink *jlink_handle;
 
 /* pid could be specified at runtime */
-static uint16_t vids[] = { VID, 0 };
-static uint16_t pids[] = { PID, 0 };
+static uint16_t vids[] = { 0x1366, 0x1366, 0x1366, 0x1366, 0x1366, 0 };
+static uint16_t pids[] = { 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0 };
 
 static uint32_t jlink_caps;
 static uint32_t jlink_hw_type;
 
+static int queued_retval;
+static bool swd_mode;
+
 /* 256 byte non-volatile memory */
 struct jlink_config {
        uint8_t usb_address;
@@ -467,7 +478,7 @@ static int jlink_select_interface(int iface)
        uint32_t iface_mask = buf_get_u32(usb_in_buffer, 0, 32);
 
        if (!(iface_mask & (1<<iface))) {
-               LOG_ERROR("J-Link requesting to select unsupported interface (%x)", iface_mask);
+               LOG_ERROR("J-Link requesting to select unsupported interface (%" PRIx32 ")", iface_mask);
                return ERROR_JTAG_DEVICE_ERROR;
        }
 
@@ -496,28 +507,6 @@ static int jlink_init(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       /*
-        * The next three instructions were added after discovering a problem
-        * while using an oscilloscope.
-        * For the V8 SAM-ICE dongle (and likely other j-link device variants),
-        * the reset line to the target microprocessor was found to cycle only
-        * intermittently during emulator startup (even after encountering the
-        * downstream reset instruction later in the code).
-        * This was found to create two issues:
-        * 1) In general it is a bad practice to not reset a CPU to a known
-        * state when starting an emulator and
-        * 2) something critical happens inside the dongle when it does the
-        * first read following a new USB session.
-        * Keeping the processor in reset during the first read collecting
-        * version information seems to prevent errant
-        * "J-Link command EMU_CMD_VERSION failed" issues.
-        */
-
-       LOG_INFO("J-Link initialization started / target CPU reset initiated");
-       jlink_simple_command(EMU_CMD_HW_TRST0);
-       jlink_simple_command(EMU_CMD_HW_RESET0);
-       usleep(1000);
-
        jlink_hw_jtag_version = 2;
 
        if (jlink_get_version_info() == ERROR_OK) {
@@ -530,11 +519,17 @@ static int jlink_init(void)
         *
         * Segger recommends to select interface necessarily as a part of init process,
         * in case any previous session leaves improper interface selected.
-        *
-        * Until SWD implemented, select only JTAG interface here.
         */
+       int retval;
        if (jlink_caps & (1<<EMU_CAP_SELECT_IF))
-               jlink_select_interface(0);
+               retval = jlink_select_interface(swd_mode ? JLINK_TIF_SWD : JLINK_TIF_JTAG);
+       else
+               retval = swd_mode ? ERROR_JTAG_DEVICE_ERROR : ERROR_OK;
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Selected transport mode is not supported.");
+               return ERROR_JTAG_INIT_FAILED;
+       }
 
        LOG_INFO("J-Link JTAG Interface ready");
 
@@ -542,11 +537,21 @@ static int jlink_init(void)
        jtag_sleep(3000);
        jlink_tap_init();
 
-       /* v5/6 jlink seems to have an issue if the first tap move
-        * is not divisible by 8, so we send a TLR on first power up */
-       for (i = 0; i < 8; i++)
-               jlink_tap_append_step(1, 0);
-       jlink_tap_execute();
+       jlink_speed(jtag_get_speed_khz());
+
+       if (!swd_mode) {
+               /* v5/6 jlink seems to have an issue if the first tap move
+                * is not divisible by 8, so we send a TLR on first power up */
+               for (i = 0; i < 8; i++)
+                       jlink_tap_append_step(1, 0);
+               jlink_tap_execute();
+       }
+
+       if (swd_mode)
+               jlink_swd_switch_seq(NULL, JTAG_TO_SWD);
+       else
+               jlink_swd_switch_seq(NULL, SWD_TO_JTAG);
+       jlink_swd_run_queue(NULL);
 
        return ERROR_OK;
 }
@@ -749,7 +754,7 @@ static void jlink_config_kickstart_dump(struct command_context *ctx, struct jlin
        if (!cfg)
                return;
 
-       jlink_dump_printf(ctx, "Kickstart power on JTAG-pin 19: 0x%x",
+       jlink_dump_printf(ctx, "Kickstart power on JTAG-pin 19: 0x%" PRIx32,
                cfg->kickstart_power_on_jtag_pin_19);
 }
 
@@ -923,7 +928,7 @@ static int jlink_get_version_info(void)
                LOG_INFO("J-Link hw version %i", (int)jlink_hw_version);
 
                if (jlink_hw_type >= JLINK_HW_TYPE_MAX)
-                       LOG_INFO("J-Link hw type uknown 0x%x", jlink_hw_type);
+                       LOG_INFO("J-Link hw type unknown 0x%" PRIx32, jlink_hw_type);
                else
                        LOG_INFO("J-Link hw type %s", jlink_hw_type_str[jlink_hw_type]);
        }
@@ -1295,10 +1300,50 @@ static const struct command_registration jlink_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
+static int jlink_swd_init(void)
+{
+       LOG_INFO("JLink SWD mode enabled");
+       swd_mode = true;
+
+       return ERROR_OK;
+}
+
+static void jlink_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
+{
+       assert(!(cmd & SWD_CMD_RnW));
+       jlink_swd_queue_cmd(dap, cmd, NULL, value);
+}
+
+static void jlink_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
+{
+       assert(cmd & SWD_CMD_RnW);
+       jlink_swd_queue_cmd(dap, cmd, value, 0);
+}
+
+static int_least32_t jlink_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+{
+       if (hz > 0)
+               jlink_speed(hz / 1000);
+
+       return hz;
+}
+
+static const struct swd_driver jlink_swd = {
+       .init = jlink_swd_init,
+       .frequency = jlink_swd_frequency,
+       .switch_seq = jlink_swd_switch_seq,
+       .read_reg = jlink_swd_read_reg,
+       .write_reg = jlink_swd_write_reg,
+       .run = jlink_swd_run_queue,
+};
+
+static const char * const jlink_transports[] = { "jtag", "swd", NULL };
+
 struct jtag_interface jlink_interface = {
        .name = "jlink",
        .commands = jlink_command_handlers,
-       .transports = jtag_only,
+       .transports = jlink_transports,
+       .swd = &jlink_swd,
 
        .execute_queue = jlink_execute_queue,
        .speed = jlink_speed,
@@ -1313,6 +1358,7 @@ struct jtag_interface jlink_interface = {
 
 
 static unsigned tap_length;
+/* In SWD mode use tms buffer for direction control */
 static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE];
 static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE];
 static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE];
@@ -1321,7 +1367,7 @@ struct pending_scan_result {
        int first;      /* First bit position in tdo_buffer to read */
        int length; /* Number of bits to read */
        struct scan_command *command; /* Corresponding scan command */
-       uint8_t *buffer;
+       void *buffer;
 };
 
 #define MAX_PENDING_SCAN_RESULTS 256
@@ -1348,11 +1394,7 @@ static void jlink_tap_append_step(int tms, int tdi)
 {
        int index_var = tap_length / 8;
 
-       if (index_var >= JLINK_TAP_BUFFER_SIZE) {
-               LOG_ERROR("jlink_tap_append_step: overflow");
-               *(uint32_t *)0xFFFFFFFF = 0;
-               exit(-1);
-       }
+       assert(index_var < JLINK_TAP_BUFFER_SIZE);
 
        int bit_index = tap_length % 8;
        uint8_t bit = 1 << bit_index;
@@ -1425,10 +1467,18 @@ static int jlink_tap_execute(void)
        jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer,
                        tap_length, jlink_last_state);
 
-       result = jlink_usb_message(jlink_handle, 4 + 2 * byte_length, byte_length);
-       if (result != byte_length) {
-               LOG_ERROR("jlink_tap_execute, wrong result %d (expected %d)",
-                               result, byte_length);
+       result = jlink_usb_message(jlink_handle, 4 + 2 * byte_length,
+                       use_jtag3 ? byte_length + 1 : byte_length);
+       if (result != ERROR_OK) {
+               LOG_ERROR("jlink_tap_execute failed USB io (%d)", result);
+               jlink_tap_init();
+               return ERROR_JTAG_QUEUE_FAILED;
+       }
+
+       result = use_jtag3 ? usb_in_buffer[byte_length] : 0;
+       if (result != 0) {
+               LOG_ERROR("jlink_tap_execute failed, result %d (%s)", result,
+                         result == 1 ? "adaptive clocking timeout" : "unknown");
                jlink_tap_init();
                return ERROR_JTAG_QUEUE_FAILED;
        }
@@ -1462,6 +1512,184 @@ static int jlink_tap_execute(void)
        return ERROR_OK;
 }
 
+static void fill_buffer(uint8_t *buf, uint32_t val, uint32_t len)
+{
+       unsigned int tap_pos = tap_length;
+
+       while (len > 32) {
+               buf_set_u32(buf, tap_pos, 32, val);
+               len -= 32;
+               tap_pos += 32;
+       }
+       if (len)
+               buf_set_u32(buf, tap_pos, len, val);
+}
+
+static void jlink_queue_data_out(const uint8_t *data, uint32_t len)
+{
+       const uint32_t dir_out = 0xffffffff;
+
+       if (data)
+               bit_copy(tdi_buffer, tap_length, data, 0, len);
+       else
+               fill_buffer(tdi_buffer, 0, len);
+       fill_buffer(tms_buffer, dir_out, len);
+       tap_length += len;
+}
+
+static void jlink_queue_data_in(uint32_t len)
+{
+       const uint32_t dir_in = 0;
+
+       fill_buffer(tms_buffer, dir_in, len);
+       tap_length += len;
+}
+
+static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+       const uint8_t *s;
+       unsigned int s_len;
+
+       switch (seq) {
+       case LINE_RESET:
+               LOG_DEBUG("SWD line reset");
+               s = swd_seq_line_reset;
+               s_len = swd_seq_line_reset_len;
+               break;
+       case JTAG_TO_SWD:
+               LOG_DEBUG("JTAG-to-SWD");
+               s = swd_seq_jtag_to_swd;
+               s_len = swd_seq_jtag_to_swd_len;
+               break;
+       case SWD_TO_JTAG:
+               LOG_DEBUG("SWD-to-JTAG");
+               s = swd_seq_swd_to_jtag;
+               s_len = swd_seq_swd_to_jtag_len;
+               break;
+       default:
+               LOG_ERROR("Sequence %d not supported", seq);
+               return ERROR_FAIL;
+       }
+
+       jlink_queue_data_out(s, s_len);
+
+       return ERROR_OK;
+}
+
+static int jlink_swd_run_queue(struct adiv5_dap *dap)
+{
+       LOG_DEBUG("Executing %d queued transactions", pending_scan_results_length);
+       int retval;
+
+       if (queued_retval != ERROR_OK) {
+               LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
+               goto skip;
+       }
+
+       /* A transaction must be followed by another transaction or at least 8 idle cycles to
+        * ensure that data is clocked through the AP. */
+       jlink_queue_data_out(NULL, 8);
+
+       size_t byte_length = DIV_ROUND_UP(tap_length, 8);
+
+       /* There's a comment in jlink_tap_execute saying JLink returns
+        * an extra NULL in packet when size of incoming message is a
+        * multiple of 64. Someone should verify if that's still the
+        * case with the current jlink firmware */
+
+       usb_out_buffer[0] = EMU_CMD_HW_JTAG3;
+       usb_out_buffer[1] = 0;
+       usb_out_buffer[2] = (tap_length >> 0) & 0xff;
+       usb_out_buffer[3] = (tap_length >> 8) & 0xff;
+       memcpy(usb_out_buffer + 4, tms_buffer, byte_length);
+       memcpy(usb_out_buffer + 4 + byte_length, tdi_buffer, byte_length);
+
+       retval = jlink_usb_message(jlink_handle, 4 + 2 * byte_length,
+                                  byte_length + 1);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("jlink_swd_run_queue failed USB io (%d)", retval);
+               goto skip;
+       }
+
+       retval = usb_in_buffer[byte_length];
+       if (retval) {
+               LOG_ERROR("jlink_swd_run_queue failed, result %d", retval);
+               goto skip;
+       }
+
+       for (int i = 0; i < pending_scan_results_length; i++) {
+               int ack = buf_get_u32(usb_in_buffer, pending_scan_results_buffer[i].first, 3);
+
+               if (ack != SWD_ACK_OK) {
+                       LOG_ERROR("SWD ack not OK: %d %s", ack,
+                                 ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
+                       queued_retval = ack;
+                       goto skip;
+               } else if (pending_scan_results_buffer[i].length) {
+                       uint32_t data = buf_get_u32(usb_in_buffer, 3 + pending_scan_results_buffer[i].first, 32);
+                       int parity = buf_get_u32(usb_in_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1);
+
+                       if (parity != parity_u32(data)) {
+                               LOG_ERROR("SWD Read data parity mismatch");
+                               queued_retval = ERROR_FAIL;
+                               goto skip;
+                       }
+
+                       if (pending_scan_results_buffer[i].buffer)
+                               *(uint32_t *)pending_scan_results_buffer[i].buffer = data;
+               }
+       }
+
+skip:
+       jlink_tap_init();
+       retval = queued_retval;
+       queued_retval = ERROR_OK;
+
+       return retval;
+}
+
+static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
+{
+       uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)];
+       if (tap_length + 46 + 8 + dap->memaccess_tck >= sizeof(tdi_buffer) * 8 ||
+           pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) {
+               /* Not enough room in the queue. Run the queue. */
+               queued_retval = jlink_swd_run_queue(dap);
+       }
+
+       if (queued_retval != ERROR_OK)
+               return;
+
+       cmd |= SWD_CMD_START | SWD_CMD_PARK;
+
+       jlink_queue_data_out(&cmd, 8);
+
+       pending_scan_results_buffer[pending_scan_results_length].first = tap_length;
+
+       if (cmd & SWD_CMD_RnW) {
+               /* Queue a read transaction */
+               pending_scan_results_buffer[pending_scan_results_length].length = 32;
+               pending_scan_results_buffer[pending_scan_results_length].buffer = dst;
+
+               jlink_queue_data_in(1 + 3 + 32 + 1 + 1);
+       } else {
+               /* Queue a write transaction */
+               pending_scan_results_buffer[pending_scan_results_length].length = 0;
+               jlink_queue_data_in(1 + 3 + 1);
+
+               buf_set_u32(data_parity_trn, 0, 32, data);
+               buf_set_u32(data_parity_trn, 32, 1, parity_u32(data));
+
+               jlink_queue_data_out(data_parity_trn, 32 + 1);
+       }
+
+       pending_scan_results_length++;
+
+       /* Insert idle cycles after AP accesses to avoid WAIT */
+       if (cmd & SWD_CMD_APnDP)
+               jlink_queue_data_out(NULL, dap->memaccess_tck);
+}
+
 /*****************************************************************************/
 /* JLink USB low-level functions */
 
@@ -1517,6 +1745,15 @@ static struct jlink *jlink_usb_open()
        usb_set_altinterface(result->usb_handle, 0);
 #endif
 
+       /* Use the OB endpoints if the JLink we matched is a Jlink-OB adapter */
+       uint16_t matched_pid;
+       if (jtag_libusb_get_pid(udev, &matched_pid) == ERROR_OK) {
+               if (matched_pid == JLINK_OB_PID) {
+                       jlink_read_ep = JLINK_OB_WRITE_ENDPOINT;
+                       jlink_write_ep = JLINK_OB_READ_ENDPOINT;
+               }
+       }
+
        jtag_libusb_get_endpoints(udev, &jlink_read_ep, &jlink_write_ep);
 
        struct jlink *result = malloc(sizeof(struct jlink));
@@ -1543,44 +1780,12 @@ static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length)
        }
 
        result = jlink_usb_read(jlink, in_length);
-       if ((result != in_length) && (result != (in_length + 1))) {
+       if (result != in_length) {
                LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)",
                                in_length, result);
                return ERROR_JTAG_DEVICE_ERROR;
        }
-
-       if (jlink_hw_jtag_version < 3)
-               return result;
-
-       int result2 = ERROR_OK;
-       if (result == in_length) {
-               /* Must read the result from the EMU too */
-               result2 = jlink_usb_read_emu_result(jlink);
-               if (1 != result2) {
-                       LOG_ERROR("jlink_usb_read_emu_result retried requested = 1, "
-                                       "result=%d, in_length=%i", result2, in_length);
-                       /* Try again once, should only happen if (in_length%64 == 0) */
-                       result2 = jlink_usb_read_emu_result(jlink);
-                       if (1 != result2) {
-                               LOG_ERROR("jlink_usb_read_emu_result failed "
-                                       "(requested = 1, result=%d)", result2);
-                               return ERROR_JTAG_DEVICE_ERROR;
-                       }
-               }
-
-               /* Check the result itself */
-               result2 = usb_emu_result_buffer[0];
-       } else {
-               /* Save the result, then remove it from return value */
-               result2 = usb_in_buffer[result--];
-       }
-
-       if (result2) {
-               LOG_ERROR("jlink_usb_message failed with result=%d)", result2);
-               return ERROR_JTAG_DEVICE_ERROR;
-       }
-
-       return result;
+       return ERROR_OK;
 }
 
 /* calls the given usb_bulk_* function, allowing for the data to
@@ -1656,19 +1861,6 @@ static int jlink_usb_read(struct jlink *jlink, int expected_size)
        return result;
 }
 
-/* Read the result from the previous EMU cmd into result_buffer. */
-static int jlink_usb_read_emu_result(struct jlink *jlink)
-{
-       int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep,
-               (char *)usb_emu_result_buffer, 1 /* JLINK_EMU_RESULT_BUFFER_SIZE */,
-               JLINK_USB_TIMEOUT);
-
-       DEBUG_JTAG_IO("jlink_usb_read_result, result = %d", result);
-
-       jlink_debug_buffer(usb_emu_result_buffer, result);
-       return result;
-}
-
 /*
  * Send a message and receive the reply - simple messages.
  *