target/xtensa: avoid IHI for writes to non-executable memory
[openocd.git] / src / jtag / drivers / jlink.c
index dd074937c9206131463c9792904ab882a84fe81e..1874557dcd5a7a8fc1483ba49f8fe990afa3134e 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net>            *
  *   based on Dominic Rath's and Benedikt Sauter's usbprog.c               *
  *                                                                         *
  *   Copyright (C) 2015 by Paul Fertser                                    *
  *   fercerpav@gmail.com                                                   *
- *                                                                         *
- *   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
@@ -38,7 +27,9 @@
 #include <jtag/interface.h>
 #include <jtag/swd.h>
 #include <jtag/commands.h>
-#include <jtag/drivers/jtag_usb_common.h>
+#include <jtag/adapter.h>
+#include <helper/replacements.h>
+#include <target/cortex_m.h>
 
 #include <libjaylink/libjaylink.h>
 
@@ -62,6 +53,9 @@ static bool trace_enabled;
 
 static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE;
 
+/* Maximum SWO frequency deviation. */
+#define SWO_MAX_FREQ_DEV       0.03
+
 /* 256 byte non-volatile memory */
 struct device_config {
        uint8_t usb_address;
@@ -90,6 +84,7 @@ static void jlink_path_move(int num_states, tap_state_t *path);
 static void jlink_stableclocks(int num_cycles);
 static void jlink_runtest(int num_cycles);
 static void jlink_reset(int trst, int srst);
+static int jlink_reset_safe(int trst, int srst);
 static int jlink_swd_run_queue(void);
 static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk);
 static int jlink_swd_switch_seq(enum swd_special_seq seq);
@@ -108,8 +103,6 @@ static int jlink_flush(void);
  * @param in A pointer to store TDO data to, if NULL the data will be discarded.
  * @param in_offset A bit offset for TDO data.
  * @param length Amount of bits to transfer out and in.
- *
- * @retval This function doesn't return any value.
  */
 static void jlink_clock_data(const uint8_t *out, unsigned out_offset,
                             const uint8_t *tms_out, unsigned tms_offset,
@@ -247,19 +240,9 @@ static void jlink_execute_scan(struct jtag_command *cmd)
                tap_state_name(tap_get_end_state()));
 }
 
-static void jlink_execute_reset(struct jtag_command *cmd)
-{
-       LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst,
-               cmd->cmd.reset->srst);
-
-       jlink_flush();
-       jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-       jlink_flush();
-}
-
 static void jlink_execute_sleep(struct jtag_command *cmd)
 {
-       LOG_DEBUG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us);
+       LOG_DEBUG_IO("sleep %" PRIu32 "", cmd->cmd.sleep->us);
        jlink_flush();
        jtag_sleep(cmd->cmd.sleep->us);
 }
@@ -282,26 +265,23 @@ static int jlink_execute_command(struct jtag_command *cmd)
                case JTAG_SCAN:
                        jlink_execute_scan(cmd);
                        break;
-               case JTAG_RESET:
-                       jlink_execute_reset(cmd);
-                       break;
                case JTAG_SLEEP:
                        jlink_execute_sleep(cmd);
                        break;
                default:
-                       LOG_ERROR("BUG: Unknown JTAG command type encountered.");
+                       LOG_ERROR("BUG: Unknown JTAG command type encountered");
                        return ERROR_JTAG_QUEUE_FAILED;
        }
 
        return ERROR_OK;
 }
 
-static int jlink_execute_queue(void)
+static int jlink_execute_queue(struct jtag_command *cmd_queue)
 {
        int ret;
-       struct jtag_command *cmd = jtag_command_queue;
+       struct jtag_command *cmd = cmd_queue;
 
-       while (cmd != NULL) {
+       while (cmd) {
                ret = jlink_execute_command(cmd);
 
                if (ret != ERROR_OK)
@@ -323,7 +303,7 @@ static int jlink_speed(int speed)
                ret = jaylink_get_speeds(devh, &tmp);
 
                if (ret != JAYLINK_OK) {
-                       LOG_ERROR("jaylink_get_speeds() failed: %s.",
+                       LOG_ERROR("jaylink_get_speeds() failed: %s",
                                jaylink_strerror(ret));
                        return ERROR_JTAG_DEVICE_ERROR;
                }
@@ -336,13 +316,13 @@ static int jlink_speed(int speed)
 
        if (!speed) {
                if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING)) {
-                       LOG_ERROR("Adaptive clocking is not supported by the device.");
+                       LOG_ERROR("Adaptive clocking is not supported by the device");
                        return ERROR_JTAG_NOT_IMPLEMENTED;
                }
 
                speed = JAYLINK_SPEED_ADAPTIVE_CLOCKING;
        } else if (speed > max_speed) {
-               LOG_INFO("Reduced speed from %d kHz to %d kHz (maximum).", speed,
+               LOG_INFO("Reduced speed from %d kHz to %d kHz (maximum)", speed,
                        max_speed);
                speed = max_speed;
        }
@@ -350,7 +330,7 @@ static int jlink_speed(int speed)
        ret = jaylink_set_speed(devh, speed);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_set_speed() failed: %s.",
+               LOG_ERROR("jaylink_set_speed() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_JTAG_DEVICE_ERROR;
        }
@@ -379,7 +359,7 @@ static bool read_device_config(struct device_config *cfg)
        ret = jaylink_read_raw_config(devh, (uint8_t *)cfg);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_read_raw_config() failed: %s.",
+               LOG_ERROR("jaylink_read_raw_config() failed: %s",
                        jaylink_strerror(ret));
                return false;
        }
@@ -400,7 +380,7 @@ static int select_interface(void)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SELECT_TIF)) {
                if (iface != JAYLINK_TIF_JTAG) {
-                       LOG_ERROR("Device supports JTAG transport only.");
+                       LOG_ERROR("Device supports JTAG transport only");
                        return ERROR_JTAG_INIT_FAILED;
                }
 
@@ -410,20 +390,20 @@ static int select_interface(void)
        ret = jaylink_get_available_interfaces(devh, &interfaces);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_available_interfaces() failed: %s.",
+               LOG_ERROR("jaylink_get_available_interfaces() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_JTAG_INIT_FAILED;
        }
 
        if (!(interfaces & (1 << iface))) {
-               LOG_ERROR("Selected transport is not supported by the device.");
+               LOG_ERROR("Selected transport is not supported by the device");
                return ERROR_JTAG_INIT_FAILED;
        }
 
        ret = jaylink_select_interface(devh, iface, NULL);
 
        if (ret < 0) {
-               LOG_ERROR("jaylink_select_interface() failed: %s.",
+               LOG_ERROR("jaylink_select_interface() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_JTAG_INIT_FAILED;
        }
@@ -444,7 +424,7 @@ static int jlink_register(void)
        ret = jaylink_register(devh, &conn, connlist, &count);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_register() failed: %s", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -459,7 +439,7 @@ static int jlink_register(void)
 
        if (!handle_found) {
                LOG_ERROR("Registration failed: maximum number of connections on the "
-                       "device reached.");
+                       "device reached");
                return ERROR_FAIL;
        }
 
@@ -482,13 +462,13 @@ static bool adjust_swd_buffer_size(void)
        ret = jaylink_get_free_memory(devh, &tmp);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_free_memory() failed: %s.",
+               LOG_ERROR("jaylink_get_free_memory() failed: %s",
                        jaylink_strerror(ret));
                return false;
        }
 
        if (tmp < 143) {
-               LOG_ERROR("Not enough free device internal memory: %u bytes.", tmp);
+               LOG_ERROR("Not enough free device internal memory: %" PRIu32 " bytes", tmp);
                return false;
        }
 
@@ -496,7 +476,7 @@ static bool adjust_swd_buffer_size(void)
 
        if (tmp != swd_buffer_size) {
                swd_buffer_size = tmp;
-               LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes.",
+               LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes",
                        swd_buffer_size);
        }
 
@@ -549,100 +529,59 @@ static bool jlink_usb_location_equal(struct jaylink_device *dev)
        if (retval == JAYLINK_ERR_NOT_SUPPORTED) {
                return false;
        } else if (retval != JAYLINK_OK) {
-               LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s.",
+               LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s",
                        jaylink_strerror(retval));
                return false;
        }
 
-       equal = jtag_usb_location_equal(bus, ports,     num_ports);
+       equal = adapter_usb_location_equal(bus, ports, num_ports);
        free(ports);
 
        return equal;
 }
 
 
-static int jlink_init(void)
+static int jlink_open_device(uint32_t ifaces, bool *found_device)
 {
-       int ret;
-       struct jaylink_device **devs;
-       unsigned int i;
-       bool found_device;
-       uint32_t tmp;
-       char *firmware_version;
-       struct jaylink_hardware_version hwver;
-       struct jaylink_hardware_status hwstatus;
-       enum jaylink_usb_address address;
-       size_t length;
-       size_t num_devices;
-       uint32_t host_interfaces;
-
-       LOG_DEBUG("Using libjaylink %s (compiled with %s).",
-               jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING);
-
-       if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) {
-               LOG_ERROR("J-Link driver does not support USB devices.");
-               return ERROR_JTAG_INIT_FAILED;
-       }
-
-       ret = jaylink_init(&jayctx);
-
-       if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror(ret));
-               return ERROR_JTAG_INIT_FAILED;
-       }
-
-       ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL);
-
-       if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_log_set_callback() failed: %s.",
-                       jaylink_strerror(ret));
-               jaylink_exit(jayctx);
-               return ERROR_JTAG_INIT_FAILED;
-       }
-
-       host_interfaces = JAYLINK_HIF_USB;
-
-       if (use_serial_number)
-               host_interfaces |= JAYLINK_HIF_TCP;
-
-       ret = jaylink_discovery_scan(jayctx, host_interfaces);
-
+       int ret = jaylink_discovery_scan(jayctx, ifaces);
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_discovery_scan() failed: %s.",
-                       jaylink_strerror(ret));
+               LOG_ERROR("jaylink_discovery_scan() failed: %s", jaylink_strerror(ret));
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
        }
 
+       size_t num_devices;
+       struct jaylink_device **devs;
        ret = jaylink_get_devices(jayctx, &devs, &num_devices);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_get_devices() failed: %s", jaylink_strerror(ret));
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       use_usb_location = (jtag_usb_get_location() != NULL);
+       use_usb_location = !!adapter_usb_get_location();
 
        if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) {
-               LOG_ERROR("Multiple devices found, specify the desired device.");
+               LOG_ERROR("Multiple devices found, specify the desired device");
                jaylink_free_devices(devs, true);
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       found_device = false;
+       *found_device = false;
 
-       for (i = 0; devs[i]; i++) {
+       for (size_t i = 0; devs[i]; i++) {
                struct jaylink_device *dev = devs[i];
 
                if (use_serial_number) {
+                       uint32_t tmp;
                        ret = jaylink_device_get_serial_number(dev, &tmp);
 
                        if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
                                continue;
                        } else if (ret != JAYLINK_OK) {
-                               LOG_WARNING("jaylink_device_get_serial_number() failed: %s.",
+                               LOG_WARNING("jaylink_device_get_serial_number() failed: %s",
                                        jaylink_strerror(ret));
                                continue;
                        }
@@ -652,12 +591,13 @@ static int jlink_init(void)
                }
 
                if (use_usb_address) {
+                       enum jaylink_usb_address address;
                        ret = jaylink_device_get_usb_address(dev, &address);
 
                        if (ret == JAYLINK_ERR_NOT_SUPPORTED) {
                                continue;
                        } else if (ret != JAYLINK_OK) {
-                               LOG_WARNING("jaylink_device_get_usb_address() failed: %s.",
+                               LOG_WARNING("jaylink_device_get_usb_address() failed: %s",
                                        jaylink_strerror(ret));
                                continue;
                        }
@@ -672,17 +612,80 @@ static int jlink_init(void)
                ret = jaylink_open(dev, &devh);
 
                if (ret == JAYLINK_OK) {
-                       found_device = true;
+                       *found_device = true;
                        break;
                }
 
-               LOG_ERROR("Failed to open device: %s.", jaylink_strerror(ret));
+               LOG_ERROR("Failed to open device: %s", jaylink_strerror(ret));
        }
 
        jaylink_free_devices(devs, true);
+       return ERROR_OK;
+}
+
+
+static int jlink_init(void)
+{
+       int ret;
+       char *firmware_version;
+       struct jaylink_hardware_version hwver;
+       struct jaylink_hardware_status hwstatus;
+       size_t length;
+
+       LOG_DEBUG("Using libjaylink %s (compiled with %s)",
+               jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING);
+
+       if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) {
+               LOG_ERROR("J-Link driver does not support USB devices");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       ret = jaylink_init(&jayctx);
+
+       if (ret != JAYLINK_OK) {
+               LOG_ERROR("jaylink_init() failed: %s", jaylink_strerror(ret));
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL);
+
+       if (ret != JAYLINK_OK) {
+               LOG_ERROR("jaylink_log_set_callback() failed: %s",
+                       jaylink_strerror(ret));
+               jaylink_exit(jayctx);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       const char *serial = adapter_get_required_serial();
+       if (serial) {
+               ret = jaylink_parse_serial_number(serial, &serial_number);
+               if (ret == JAYLINK_ERR) {
+                       LOG_ERROR("Invalid serial number: %s", serial);
+                       jaylink_exit(jayctx);
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+               if (ret != JAYLINK_OK) {
+                       LOG_ERROR("jaylink_parse_serial_number() failed: %s", jaylink_strerror(ret));
+                       jaylink_exit(jayctx);
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+               use_serial_number = true;
+               use_usb_address = false;
+       }
+
+       bool found_device;
+       ret = jlink_open_device(JAYLINK_HIF_USB, &found_device);
+       if (ret != ERROR_OK)
+               return ret;
+
+       if (!found_device && use_serial_number) {
+               ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device);
+               if (ret != ERROR_OK)
+                       return ret;
+       }
 
        if (!found_device) {
-               LOG_ERROR("No J-Link device found.");
+               LOG_ERROR("No J-Link device found");
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
        }
@@ -695,7 +698,7 @@ static int jlink_init(void)
        ret = jaylink_get_firmware_version(devh, &firmware_version, &length);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_firmware_version() failed: %s.",
+               LOG_ERROR("jaylink_get_firmware_version() failed: %s",
                        jaylink_strerror(ret));
                jaylink_close(devh);
                jaylink_exit(jayctx);
@@ -704,14 +707,14 @@ static int jlink_init(void)
                LOG_INFO("%s", firmware_version);
                free(firmware_version);
        } else {
-               LOG_WARNING("Device responds empty firmware version string.");
+               LOG_WARNING("Device responds empty firmware version string");
        }
 
        memset(caps, 0, JAYLINK_DEV_EXT_CAPS_SIZE);
        ret = jaylink_get_caps(devh, caps);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_get_caps() failed: %s", jaylink_strerror(ret));
                jaylink_close(devh);
                jaylink_exit(jayctx);
                return ERROR_JTAG_INIT_FAILED;
@@ -721,7 +724,7 @@ static int jlink_init(void)
                ret = jaylink_get_extended_caps(devh, caps);
 
                if (ret != JAYLINK_OK) {
-                       LOG_ERROR("jaylink_get_extended_caps() failed:  %s.",
+                       LOG_ERROR("jaylink_get_extended_caps() failed:  %s",
                                jaylink_strerror(ret));
                        jaylink_close(devh);
                        jaylink_exit(jayctx);
@@ -735,7 +738,7 @@ static int jlink_init(void)
                ret = jaylink_get_hardware_version(devh, &hwver);
 
                if (ret != JAYLINK_OK) {
-                       LOG_ERROR("Failed to retrieve hardware version: %s.",
+                       LOG_ERROR("Failed to retrieve hardware version: %s",
                                jaylink_strerror(ret));
                        jaylink_close(devh);
                        jaylink_exit(jayctx);
@@ -764,7 +767,7 @@ static int jlink_init(void)
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
                if (!read_device_config(&config)) {
-                       LOG_ERROR("Failed to read device configuration data.");
+                       LOG_ERROR("Failed to read device configuration data");
                        jaylink_close(devh);
                        jaylink_exit(jayctx);
                        return ERROR_JTAG_INIT_FAILED;
@@ -776,7 +779,7 @@ static int jlink_init(void)
        ret = jaylink_get_hardware_status(devh, &hwstatus);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_hardware_status() failed: %s.",
+               LOG_ERROR("jaylink_get_hardware_status() failed: %s",
                        jaylink_strerror(ret));
                jaylink_close(devh);
                jaylink_exit(jayctx);
@@ -812,7 +815,7 @@ static int jlink_init(void)
        jtag_sleep(3000);
        jlink_tap_init();
 
-       jlink_speed(jtag_get_speed_khz());
+       jlink_speed(adapter_get_speed_khz());
 
        if (iface == JAYLINK_TIF_JTAG) {
                /*
@@ -838,14 +841,14 @@ static int jlink_quit(void)
                ret = jaylink_swo_stop(devh);
 
                if (ret != JAYLINK_OK)
-                       LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret));
+                       LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret));
        }
 
        if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) {
                ret = jaylink_unregister(devh, &conn, connlist, &count);
 
                if (ret != JAYLINK_OK)
-                       LOG_ERROR("jaylink_unregister() failed: %s.",
+                       LOG_ERROR("jaylink_unregister() failed: %s",
                                jaylink_strerror(ret));
        }
 
@@ -893,7 +896,7 @@ static void jlink_path_move(int num_states, tap_state_t *path)
                else if (path[i] == tap_state_transition(tap_get_state(), true))
                        jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1);
                else {
-                       LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.",
+                       LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
                                tap_state_name(tap_get_state()), tap_state_name(path[i]));
                        exit(-1);
                }
@@ -936,7 +939,7 @@ static void jlink_runtest(int num_cycles)
 
 static void jlink_reset(int trst, int srst)
 {
-       LOG_DEBUG("TRST: %i, SRST: %i.", trst, srst);
+       LOG_DEBUG("TRST: %i, SRST: %i", trst, srst);
 
        /* Signals are active low. */
        if (srst == 0)
@@ -952,59 +955,37 @@ static void jlink_reset(int trst, int srst)
                jaylink_jtag_set_trst(devh);
 }
 
+static int jlink_reset_safe(int trst, int srst)
+{
+       jlink_flush();
+       jlink_reset(trst, srst);
+       return jlink_flush();
+}
+
 COMMAND_HANDLER(jlink_usb_command)
 {
        int tmp;
 
-       if (CMD_ARGC != 1) {
-               command_print(CMD, "Need exactly one argument for jlink usb.");
+       if (CMD_ARGC != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) {
-               command_print(CMD, "Invalid USB address: %s.", CMD_ARGV[0]);
-               return ERROR_FAIL;
+               command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
        }
 
        if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) {
-               command_print(CMD, "Invalid USB address: %s.", CMD_ARGV[0]);
-               return ERROR_FAIL;
+               command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
        }
 
        usb_address = tmp;
 
-       use_serial_number = false;
        use_usb_address = true;
 
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(jlink_serial_command)
-{
-       int ret;
-
-       if (CMD_ARGC != 1) {
-               command_print(CMD, "Need exactly one argument for jlink serial.");
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
-       ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number);
-
-       if (ret == JAYLINK_ERR) {
-               command_print(CMD, "Invalid serial number: %s.", CMD_ARGV[0]);
-               return ERROR_FAIL;
-       } else if (ret != JAYLINK_OK) {
-               command_print(CMD, "jaylink_parse_serial_number() failed: %s.",
-                       jaylink_strerror(ret));
-               return ERROR_FAIL;
-       }
-
-       use_serial_number = true;
-       use_usb_address = false;
-
-       return ERROR_OK;
-}
-
 COMMAND_HANDLER(jlink_handle_hwstatus_command)
 {
        int ret;
@@ -1013,7 +994,7 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command)
        ret = jaylink_get_hardware_status(devh, &status);
 
        if (ret != JAYLINK_OK) {
-               command_print(CMD, "jaylink_get_hardware_status() failed: %s.",
+               command_print(CMD, "jaylink_get_hardware_status() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_FAIL;
        }
@@ -1026,7 +1007,7 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command)
                status.tres, status.trst);
 
        if (status.target_voltage < 1500)
-               command_print(CMD, "Target voltage too low. Check target power.");
+               command_print(CMD, "Target voltage too low. Check target power");
 
        return ERROR_OK;
 }
@@ -1038,19 +1019,19 @@ COMMAND_HANDLER(jlink_handle_free_memory_command)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) {
                command_print(CMD, "Retrieval of free memory is not supported by "
-                       "the device.");
+                       "the device");
                return ERROR_OK;
        }
 
        ret = jaylink_get_free_memory(devh, &tmp);
 
        if (ret != JAYLINK_OK) {
-               command_print(CMD, "jaylink_get_free_memory() failed: %s.",
+               command_print(CMD, "jaylink_get_free_memory() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
-       command_print(CMD, "Device has %u bytes of free memory.", tmp);
+       command_print(CMD, "Device has %" PRIu32 " bytes of free memory", tmp);
 
        return ERROR_OK;
 }
@@ -1075,8 +1056,8 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command)
                command_print(CMD, "JTAG command version: %i", version);
        } else if (CMD_ARGC == 1) {
                if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) {
-                       command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+                       command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                switch (tmp) {
@@ -1087,11 +1068,10 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command)
                                jtag_command_version = JAYLINK_JTAG_VERSION_3;
                                break;
                        default:
-                               command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
-                               return ERROR_COMMAND_SYNTAX_ERROR;
+                               command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]);
+                               return ERROR_COMMAND_ARGUMENT_INVALID;
                }
        } else {
-               command_print(CMD, "Need exactly one argument for jlink jtag.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
@@ -1103,15 +1083,12 @@ COMMAND_HANDLER(jlink_handle_target_power_command)
        int ret;
        int enable;
 
-       if (CMD_ARGC != 1) {
-               command_print(CMD, "Need exactly one argument for jlink "
-                       "targetpower.");
+       if (CMD_ARGC != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) {
                command_print(CMD, "Target power supply is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
@@ -1120,14 +1097,14 @@ COMMAND_HANDLER(jlink_handle_target_power_command)
        } else if (!strcmp(CMD_ARGV[0], "off")) {
                enable = false;
        } else {
-               command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
+               command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]);
                return ERROR_FAIL;
        }
 
        ret = jaylink_set_target_power(devh, enable);
 
        if (ret != JAYLINK_OK) {
-               command_print(CMD, "jaylink_set_target_power() failed: %s.",
+               command_print(CMD, "jaylink_set_target_power() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_FAIL;
        }
@@ -1234,7 +1211,7 @@ static int poll_trace(uint8_t *buf, size_t *size)
        ret = jaylink_swo_read(devh, buf, &length);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_swo_read() failed: %s", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1254,7 +1231,7 @@ static uint32_t calculate_trace_buffer_size(void)
        ret = jaylink_get_free_memory(devh, &tmp);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_get_free_memory() failed: %s.",
+               LOG_ERROR("jaylink_get_free_memory() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_FAIL;
        }
@@ -1267,59 +1244,75 @@ static uint32_t calculate_trace_buffer_size(void)
        return tmp & 0xffffff00;
 }
 
-static bool check_trace_freq(struct jaylink_swo_speed speed,
-               uint32_t trace_freq)
+static bool calculate_swo_prescaler(unsigned int traceclkin_freq,
+               uint32_t trace_freq, uint16_t *prescaler)
+{
+       unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq;
+       if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1)
+               return false;
+
+       /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */
+       unsigned int max_deviation = (traceclkin_freq * 3) / 100;
+       if (presc * trace_freq < traceclkin_freq - max_deviation ||
+           presc * trace_freq > traceclkin_freq + max_deviation)
+               return false;
+
+       *prescaler = presc;
+
+       return true;
+}
+
+static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed,
+               unsigned int traceclkin_freq, unsigned int *trace_freq,
+               uint16_t *prescaler)
 {
-       double min;
-       double deviation;
        uint32_t divider;
+       unsigned int presc;
+       double deviation;
+
+       for (divider = speed.min_div; divider <= speed.max_div; divider++) {
+               *trace_freq = speed.freq / divider;
+               presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1;
 
-       min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div)));
+               if (presc > TPIU_ACPR_MAX_SWOSCALER + 1)
+                       break;
 
-       for (divider = speed.min_div; divider < speed.max_div; divider++) {
-               deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider)));
+               deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq));
 
-               if (deviation < 0.03) {
-                       LOG_DEBUG("Found suitable frequency divider %u with deviation of "
-                               "%.02f %%.", divider, deviation);
+               if (deviation <= SWO_MAX_FREQ_DEV) {
+                       *prescaler = presc;
                        return true;
                }
-
-               if (deviation < min)
-                       min = deviation;
        }
 
-       LOG_ERROR("Selected trace frequency is not supported by the device. "
-               "Please choose a different trace frequency.");
-       LOG_ERROR("Maximum permitted deviation is 3.00 %%, but only %.02f %% "
-               "could be achieved.", min * 100);
-
        return false;
 }
 
 static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
-               uint32_t port_size, unsigned int *trace_freq)
+               uint32_t port_size, unsigned int *trace_freq,
+               unsigned int traceclkin_freq, uint16_t *prescaler)
 {
        int ret;
        uint32_t buffer_size;
        struct jaylink_swo_speed speed;
+       uint32_t divider;
+       uint32_t min_freq;
+       uint32_t max_freq;
+
+       trace_enabled = enabled;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) {
-               LOG_ERROR("Trace capturing is not supported by the device.");
-               return ERROR_FAIL;
-       }
+               if (!enabled)
+                       return ERROR_OK;
 
-       if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
-               LOG_ERROR("Selected pin protocol is not supported.");
+               LOG_ERROR("Trace capturing is not supported by the device");
                return ERROR_FAIL;
        }
 
-       trace_enabled = enabled;
-
        ret = jaylink_swo_stop(devh);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
@@ -1334,37 +1327,77 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
                return ERROR_OK;
        }
 
+       if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
+               LOG_ERROR("Selected pin protocol is not supported");
+               return ERROR_FAIL;
+       }
+
        buffer_size = calculate_trace_buffer_size();
 
        if (!buffer_size) {
-               LOG_ERROR("Not enough free device memory to start trace capturing.");
+               LOG_ERROR("Not enough free device memory to start trace capturing");
                return ERROR_FAIL;
        }
 
        ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &speed);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swo_get_speeds() failed: %s.",
+               LOG_ERROR("jaylink_swo_get_speeds() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
-       if (!*trace_freq)
-               *trace_freq = speed.freq / speed.min_div;
+       if (*trace_freq > 0) {
+               divider = speed.freq / *trace_freq;
+               min_freq = speed.freq / speed.max_div;
+               max_freq = speed.freq / speed.min_div;
+
+               if (*trace_freq > max_freq) {
+                       LOG_INFO("Given SWO frequency too high, using %" PRIu32 " Hz instead",
+                               max_freq);
+                       *trace_freq = max_freq;
+               } else if (*trace_freq < min_freq) {
+                       LOG_INFO("Given SWO frequency too low, using %" PRIu32 " Hz instead",
+                               min_freq);
+                       *trace_freq = min_freq;
+               } else if (*trace_freq != speed.freq / divider) {
+                       *trace_freq = speed.freq / divider;
+
+                       LOG_INFO("Given SWO frequency is not supported by the device, "
+                               "using %u Hz instead", *trace_freq);
+               }
+
+               if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq,
+                               prescaler)) {
+                       LOG_ERROR("SWO frequency is not suitable. Please choose a "
+                               "different frequency or use auto-detection");
+                       return ERROR_FAIL;
+               }
+       } else {
+               LOG_INFO("Trying to auto-detect SWO frequency");
 
-       if (!check_trace_freq(speed, *trace_freq))
-               return ERROR_FAIL;
+               if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq,
+                               prescaler)) {
+                       LOG_ERROR("Maximum permitted frequency deviation of %.02f %% "
+                               "could not be achieved", SWO_MAX_FREQ_DEV);
+                       LOG_ERROR("Auto-detection of SWO frequency failed");
+                       return ERROR_FAIL;
+               }
 
-       LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size);
+               LOG_INFO("Using SWO frequency of %u Hz", *trace_freq);
+       }
 
        ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq,
                buffer_size);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_start_swo() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_start_swo() failed: %s", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
+       LOG_DEBUG("Using %" PRIu32 " bytes device memory for trace capturing",
+               buffer_size);
+
        /*
         * Adjust the SWD transaction buffer size as starting SWO capturing
         * allocates device internal memory.
@@ -1381,7 +1414,7 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
                command_print(CMD, "Reading configuration is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
@@ -1389,19 +1422,17 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command)
                show_config_usb_address(CMD);
        } else if (CMD_ARGC == 1) {
                if (sscanf(CMD_ARGV[0], "%" SCNd8, &tmp) != 1) {
-                       command_print(CMD, "Invalid USB address: %s.", CMD_ARGV[0]);
-                       return ERROR_FAIL;
+                       command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                if (tmp > JAYLINK_USB_ADDRESS_3) {
-                       command_print(CMD, "Invalid USB address: %u.", tmp);
-                       return ERROR_FAIL;
+                       command_print(CMD, "Invalid USB address: %u", tmp);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                tmp_config.usb_address = tmp;
        } else {
-               command_print(CMD, "Need exactly one argument for jlink config "
-                       "usb.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
@@ -1414,13 +1445,13 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
                command_print(CMD, "Reading configuration is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) {
                command_print(CMD, "Target power supply is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
@@ -1432,14 +1463,12 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command)
                } else if (!strcmp(CMD_ARGV[0], "off")) {
                        enable = false;
                } else {
-                       command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]);
-                       return ERROR_FAIL;
+                       command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                tmp_config.target_power = enable;
        } else {
-               command_print(CMD, "Need exactly one argument for jlink config "
-                       "targetpower.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
@@ -1455,13 +1484,13 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
                command_print(CMD, "Reading configuration is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) {
                command_print(CMD, "Ethernet connectivity is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
@@ -1470,10 +1499,10 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
        } else if (CMD_ARGC == 1) {
                str = CMD_ARGV[0];
 
-               if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || \
+               if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' ||
                                str[8] != ':' || str[11] != ':' || str[14] != ':')) {
-                       command_print(CMD, "Invalid MAC address format.");
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+                       command_print(CMD, "Invalid MAC address format");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                for (i = 5; i >= 0; i--) {
@@ -1482,19 +1511,17 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
                }
 
                if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) {
-                       command_print(CMD, "Invalid MAC address: zero address.");
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+                       command_print(CMD, "Invalid MAC address: zero address");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                if (!(0x01 & addr[0])) {
-                       command_print(CMD, "Invalid MAC address: multicast address.");
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+                       command_print(CMD, "Invalid MAC address: multicast address");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
                }
 
                memcpy(tmp_config.mac_address, addr, sizeof(addr));
        } else {
-               command_print(CMD, "Need exactly one argument for jlink config "
-                       " mac.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
@@ -1543,33 +1570,39 @@ COMMAND_HANDLER(jlink_handle_config_ip_address_command)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
                command_print(CMD, "Reading configuration is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) {
                command_print(CMD, "Ethernet connectivity is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
        if (!CMD_ARGC) {
                show_config_ip_address(CMD);
        } else {
-               if (!string_to_ip(CMD_ARGV[0], ip_address, &i))
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               if (!string_to_ip(CMD_ARGV[0], ip_address, &i)) {
+                       command_print(CMD, "invalid IPv4 address");
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
 
                len = strlen(CMD_ARGV[0]);
 
                /* Check for format A.B.C.D/E. */
                if (i < len) {
-                       if (CMD_ARGV[0][i] != '/')
-                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       if (CMD_ARGV[0][i] != '/') {
+                               command_print(CMD, "missing network mask");
+                               return ERROR_COMMAND_ARGUMENT_INVALID;
+                       }
 
                        COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0] + i + 1, subnet_bits);
                } else if (CMD_ARGC > 1) {
-                       if (!string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i))
-                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       if (!string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i)) {
+                               command_print(CMD, "invalid subnet mask");
+                               return ERROR_COMMAND_ARGUMENT_INVALID;
+                       }
                }
 
                if (!subnet_mask)
@@ -1600,44 +1633,44 @@ COMMAND_HANDLER(jlink_handle_config_write_command)
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
                command_print(CMD, "Reading configuration is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_WRITE_CONFIG)) {
                command_print(CMD, "Writing configuration is not supported by the "
-                       "device.");
+                       "device");
                return ERROR_OK;
        }
 
        if (!memcmp(&config, &tmp_config, sizeof(struct device_config))) {
                command_print(CMD, "Operation not performed due to no changes in "
-                       "the configuration.");
+                       "the configuration");
                return ERROR_OK;
        }
 
        ret = jaylink_write_raw_config(devh, (const uint8_t *)&tmp_config);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_write_raw_config() failed: %s.",
+               LOG_ERROR("jaylink_write_raw_config() failed: %s",
                        jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
        if (!read_device_config(&config)) {
-               LOG_ERROR("Failed to read device configuration for verification.");
+               LOG_ERROR("Failed to read device configuration for verification");
                return ERROR_FAIL;
        }
 
        if (memcmp(&config, &tmp_config, sizeof(struct device_config))) {
                LOG_ERROR("Verification of device configuration failed. Please check "
-                       "your device.");
+                       "your device");
                return ERROR_FAIL;
        }
 
        memcpy(&tmp_config, &config, sizeof(struct device_config));
        command_print(CMD, "The new device configuration applies after power "
-               "cycling the J-Link device.");
+               "cycling the J-Link device");
 
        return ERROR_OK;
 }
@@ -1645,7 +1678,7 @@ COMMAND_HANDLER(jlink_handle_config_write_command)
 COMMAND_HANDLER(jlink_handle_config_command)
 {
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) {
-               command_print(CMD, "Device doesn't support reading configuration.");
+               command_print(CMD, "Device doesn't support reading configuration");
                return ERROR_OK;
        }
 
@@ -1668,7 +1701,7 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
-               LOG_ERROR("Device does not support EMUCOM.");
+               LOG_ERROR("Device does not support EMUCOM");
                return ERROR_FAIL;
        }
 
@@ -1677,21 +1710,21 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command)
        tmp = strlen(CMD_ARGV[1]);
 
        if (tmp % 2 != 0) {
-               LOG_ERROR("Data must be encoded as hexadecimal pairs.");
+               LOG_ERROR("Data must be encoded as hexadecimal pairs");
                return ERROR_COMMAND_ARGUMENT_INVALID;
        }
 
        buf = malloc(tmp / 2);
 
        if (!buf) {
-               LOG_ERROR("Failed to allocate buffer.");
+               LOG_ERROR("Failed to allocate buffer");
                return ERROR_FAIL;
        }
 
        dummy = unhexify(buf, CMD_ARGV[1], tmp / 2);
 
        if (dummy != (tmp / 2)) {
-               LOG_ERROR("Data must be encoded as hexadecimal pairs.");
+               LOG_ERROR("Data must be encoded as hexadecimal pairs");
                free(buf);
                return ERROR_COMMAND_ARGUMENT_INVALID;
        }
@@ -1702,15 +1735,15 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command)
        free(buf);
 
        if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
-               LOG_ERROR("Channel not supported by the device.");
+               LOG_ERROR("Channel not supported by the device");
                return ERROR_FAIL;
        } else if (ret != JAYLINK_OK) {
-               LOG_ERROR("Failed to write to channel: %s.", jaylink_strerror(ret));
+               LOG_ERROR("Failed to write to channel: %s", jaylink_strerror(ret));
                return ERROR_FAIL;
        }
 
        if (length != (tmp / 2))
-               LOG_WARNING("Only %" PRIu32 " bytes written to the channel.", length);
+               LOG_WARNING("Only %" PRIu32 " bytes written to the channel", length);
 
        return ERROR_OK;
 }
@@ -1727,7 +1760,7 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) {
-               LOG_ERROR("Device does not support EMUCOM.");
+               LOG_ERROR("Device does not support EMUCOM");
                return ERROR_FAIL;
        }
 
@@ -1737,23 +1770,23 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command)
        buf = malloc(length * 3 + 1);
 
        if (!buf) {
-               LOG_ERROR("Failed to allocate buffer.");
+               LOG_ERROR("Failed to allocate buffer");
                return ERROR_FAIL;
        }
 
        ret = jaylink_emucom_read(devh, channel, buf, &length);
 
        if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) {
-               LOG_ERROR("Channel is not supported by the device.");
+               LOG_ERROR("Channel is not supported by the device");
                free(buf);
                return ERROR_FAIL;
        } else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) {
                LOG_ERROR("Channel is not available for the requested amount of data. "
-                       "%" PRIu32 " bytes are avilable.", length);
+                       "%" PRIu32 " bytes are available", length);
                free(buf);
                return ERROR_FAIL;
        } else if (ret != JAYLINK_OK) {
-               LOG_ERROR("Failed to read from channel: %s.", jaylink_strerror(ret));
+               LOG_ERROR("Failed to read from channel: %s", jaylink_strerror(ret));
                free(buf);
                return ERROR_FAIL;
        }
@@ -1761,7 +1794,7 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command)
        tmp = hexify((char *)buf + length, buf, length, 2 * length + 1);
 
        if (tmp != 2 * length) {
-               LOG_ERROR("Failed to convert data into hexadecimal string.");
+               LOG_ERROR("Failed to convert data into hexadecimal string");
                free(buf);
                return ERROR_FAIL;
        }
@@ -1873,13 +1906,6 @@ static const struct command_registration jlink_subcommand_handlers[] = {
                .help = "set the USB address of the device that should be used",
                .usage = "<0-3>"
        },
-       {
-               .name = "serial",
-               .handler = &jlink_serial_command,
-               .mode = COMMAND_CONFIG,
-               .help = "set the serial number of the device that should be used",
-               .usage = "<serial number>"
-       },
        {
                .name = "config",
                .handler = &jlink_handle_config_command,
@@ -1919,24 +1945,16 @@ static int jlink_swd_init(void)
 
 static void jlink_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
 {
-       assert(!(cmd & SWD_CMD_RnW));
+       assert(!(cmd & SWD_CMD_RNW));
        jlink_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
 }
 
 static void jlink_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
 {
-       assert(cmd & SWD_CMD_RnW);
+       assert(cmd & SWD_CMD_RNW);
        jlink_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
 }
 
-static int_least32_t jlink_swd_frequency(int_least32_t hz)
-{
-       if (hz > 0)
-               jlink_speed(hz / 1000);
-
-       return hz;
-}
-
 /***************************************************************************/
 /* J-Link tap functions */
 
@@ -1955,6 +1973,8 @@ struct pending_scan_result {
        void *buffer;
        /** Offset in the destination buffer */
        unsigned buffer_offset;
+       /** SWD command */
+       uint8_t swd_cmd;
 };
 
 #define MAX_PENDING_SCAN_RESULTS 256
@@ -2027,7 +2047,7 @@ static int jlink_flush(void)
                tap_length, jtag_command_version);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_jtag_io() failed: %s", jaylink_strerror(ret));
                jlink_tap_init();
                return ERROR_JTAG_QUEUE_FAILED;
        }
@@ -2038,7 +2058,7 @@ static int jlink_flush(void)
                buf_set_buf(tdo_buffer, p->first, p->buffer,
                            p->buffer_offset, p->length);
 
-               LOG_DEBUG_IO("Pending scan result, length = %d.", p->length);
+               LOG_DEBUG_IO("Pending scan result, length = %d", p->length);
        }
 
        jlink_tap_init();
@@ -2088,7 +2108,7 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq)
 
        switch (seq) {
                case LINE_RESET:
-                       LOG_DEBUG("SWD line reset");
+                       LOG_DEBUG_IO("SWD line reset");
                        s = swd_seq_line_reset;
                        s_len = swd_seq_line_reset_len;
                        break;
@@ -2097,13 +2117,33 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq)
                        s = swd_seq_jtag_to_swd;
                        s_len = swd_seq_jtag_to_swd_len;
                        break;
+               case JTAG_TO_DORMANT:
+                       LOG_DEBUG("JTAG-to-DORMANT");
+                       s = swd_seq_jtag_to_dormant;
+                       s_len = swd_seq_jtag_to_dormant_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;
+               case SWD_TO_DORMANT:
+                       LOG_DEBUG("SWD-to-DORMANT");
+                       s = swd_seq_swd_to_dormant;
+                       s_len = swd_seq_swd_to_dormant_len;
+                       break;
+               case DORMANT_TO_SWD:
+                       LOG_DEBUG("DORMANT-to-SWD");
+                       s = swd_seq_dormant_to_swd;
+                       s_len = swd_seq_dormant_to_swd_len;
+                       break;
+               case DORMANT_TO_JTAG:
+                       LOG_DEBUG("DORMANT-to-JTAG");
+                       s = swd_seq_dormant_to_jtag;
+                       s_len = swd_seq_dormant_to_jtag_len;
+                       break;
                default:
-                       LOG_ERROR("Sequence %d not supported.", seq);
+                       LOG_ERROR("Sequence %d not supported", seq);
                        return ERROR_FAIL;
        }
 
@@ -2117,10 +2157,10 @@ static int jlink_swd_run_queue(void)
        int i;
        int ret;
 
-       LOG_DEBUG("Executing %d queued transactions.", pending_scan_results_length);
+       LOG_DEBUG_IO("Executing %d queued transactions", pending_scan_results_length);
 
        if (queued_retval != ERROR_OK) {
-               LOG_DEBUG("Skipping due to previous errors: %d.", queued_retval);
+               LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
                goto skip;
        }
 
@@ -2133,24 +2173,25 @@ static int jlink_swd_run_queue(void)
        ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length);
 
        if (ret != JAYLINK_OK) {
-               LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror(ret));
+               LOG_ERROR("jaylink_swd_io() failed: %s", jaylink_strerror(ret));
                goto skip;
        }
 
        for (i = 0; i < pending_scan_results_length; i++) {
+               /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
+               bool check_ack = swd_cmd_returns_ack(pending_scan_results_buffer[i].swd_cmd);
                int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3);
-
-               if (ack != SWD_ACK_OK) {
+               if (check_ack && ack != SWD_ACK_OK) {
                        LOG_DEBUG("SWD ack not OK: %d %s", ack,
                                  ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
-                       queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
+                       queued_retval = swd_ack_to_error_code(ack);
                        goto skip;
                } else if (pending_scan_results_buffer[i].length) {
                        uint32_t data = buf_get_u32(tdo_buffer, 3 + pending_scan_results_buffer[i].first, 32);
                        int parity = buf_get_u32(tdo_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1);
 
                        if (parity != parity_u32(data)) {
-                               LOG_ERROR("SWD: Read data parity mismatch.");
+                               LOG_ERROR("SWD: Read data parity mismatch");
                                queued_retval = ERROR_FAIL;
                                goto skip;
                        }
@@ -2180,13 +2221,14 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3
        if (queued_retval != ERROR_OK)
                return;
 
+       pending_scan_results_buffer[pending_scan_results_length].swd_cmd = cmd;
        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) {
+       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;
@@ -2206,13 +2248,12 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3
        pending_scan_results_length++;
 
        /* Insert idle cycles after AP accesses to avoid WAIT. */
-       if (cmd & SWD_CMD_APnDP)
+       if (cmd & SWD_CMD_APNDP)
                jlink_queue_data_out(NULL, ap_delay_clk);
 }
 
 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,
@@ -2221,17 +2262,24 @@ static const struct swd_driver jlink_swd = {
 
 static const char * const jlink_transports[] = { "jtag", "swd", NULL };
 
-struct jtag_interface jlink_interface = {
+static struct jtag_interface jlink_interface = {
+       .execute_queue = &jlink_execute_queue,
+};
+
+struct adapter_driver jlink_adapter_driver = {
        .name = "jlink",
-       .commands = jlink_command_handlers,
        .transports = jlink_transports,
-       .swd = &jlink_swd,
-       .execute_queue = &jlink_execute_queue,
-       .speed = &jlink_speed,
-       .speed_div = &jlink_speed_div,
-       .khz = &jlink_khz,
+       .commands = jlink_command_handlers,
+
        .init = &jlink_init,
        .quit = &jlink_quit,
+       .reset = &jlink_reset_safe,
+       .speed = &jlink_speed,
+       .khz = &jlink_khz,
+       .speed_div = &jlink_speed_div,
        .config_trace = &config_trace,
        .poll_trace = &poll_trace,
+
+       .jtag_ops = &jlink_interface,
+       .swd_ops = &jlink_swd,
 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)