X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fjlink.c;h=1874557dcd5a7a8fc1483ba49f8fe990afa3134e;hb=HEAD;hp=7a2be61fe26ef83f69fdafdb8cb3b194aefe34bd;hpb=1887e2a273797af3d5625ea3d78df3f9ce27ead3;p=openocd.git diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 7a2be61fe2..1874557dcd 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Juergen Stuber * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * @@ -13,19 +15,6 @@ * * * 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 . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -38,8 +27,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -114,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, @@ -289,12 +276,12 @@ static int jlink_execute_command(struct jtag_command *cmd) 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) @@ -547,7 +534,7 @@ static bool jlink_usb_location_equal(struct jaylink_device *dev) return false; } - equal = jtag_usb_location_equal(bus, ports, num_ports); + equal = adapter_usb_location_equal(bus, ports, num_ports); free(ports); return equal; @@ -573,7 +560,7 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) 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"); @@ -669,6 +656,23 @@ static int jlink_init(void) 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) @@ -811,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) { /* @@ -962,55 +966,26 @@ 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; + 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; + 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; @@ -1082,7 +1057,7 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) } 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; + return ERROR_COMMAND_ARGUMENT_INVALID; } switch (tmp) { @@ -1094,10 +1069,9 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) break; default: command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } } else { - command_print(CMD, "Need exactly one argument for jlink jtag"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1109,10 +1083,8 @@ 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 " @@ -1451,17 +1423,16 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command) } 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; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %u", tmp); - return ERROR_FAIL; + 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; } @@ -1493,13 +1464,11 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command) enable = false; } else { command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_FAIL; + 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; } @@ -1533,7 +1502,7 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command) 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; + return ERROR_COMMAND_ARGUMENT_INVALID; } for (i = 5; i >= 0; i--) { @@ -1543,17 +1512,16 @@ 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; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (!(0x01 & addr[0])) { command_print(CMD, "Invalid MAC address: multicast address"); - return ERROR_COMMAND_SYNTAX_ERROR; + 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; } @@ -1615,20 +1583,26 @@ COMMAND_HANDLER(jlink_handle_config_ip_address_command) 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) @@ -1932,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 = "" - }, { .name = "config", .handler = &jlink_handle_config_command, @@ -2006,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 @@ -2139,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; @@ -2148,11 +2117,31 @@ 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); return ERROR_FAIL; @@ -2168,7 +2157,7 @@ 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); @@ -2189,12 +2178,13 @@ static int jlink_swd_run_queue(void) } 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); @@ -2231,6 +2221,7 @@ 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);