diff --git a/src/command.c b/src/command.c index 73fe65a90c9..987d25468ec 100644 --- a/src/command.c +++ b/src/command.c @@ -487,7 +487,8 @@ static bool cmd_target_power(target_s *t, int argc, const char **argv) /* want to enable target power, but VREF > 0.5V sensed -> cancel */ gdb_outf("Target already powered (%s)\n", platform_target_voltage()); } else { - platform_target_set_power(want_enable); + if (!platform_target_set_power(want_enable)) + DEBUG_ERROR("%s target power failed\n", want_enable ? "Enabling" : "Disabling"); gdb_outf("%s target power\n", want_enable ? "Enabling" : "Disabling"); } } diff --git a/src/include/platform_support.h b/src/include/platform_support.h index 3a22fa4a002..88f822f702f 100644 --- a/src/include/platform_support.h +++ b/src/include/platform_support.h @@ -55,7 +55,7 @@ int platform_hwversion(void); void platform_nrst_set_val(bool assert); bool platform_nrst_get_val(void); bool platform_target_get_power(void); -void platform_target_set_power(bool power); +bool platform_target_set_power(bool power); void platform_request_boot(void); void platform_max_frequency_set(uint32_t frequency); uint32_t platform_max_frequency_get(void); diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 32cf3ebeab1..db3433143d1 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -151,9 +151,10 @@ bool platform_target_get_power(void) return gpio_get(PWR_BR_PORT, PWR_BR_PIN); } -void platform_target_set_power(const bool power) +bool platform_target_set_power(const bool power) { gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, power); + return true; } /* diff --git a/src/platforms/f4discovery/platform.c b/src/platforms/f4discovery/platform.c index d64e947487b..3fc5c95246f 100644 --- a/src/platforms/f4discovery/platform.c +++ b/src/platforms/f4discovery/platform.c @@ -139,9 +139,10 @@ bool platform_target_get_power(void) return !gpio_get(PWR_BR_PORT, PWR_BR_PIN); } -void platform_target_set_power(const bool power) +bool platform_target_set_power(const bool power) { gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power); + return true; } #endif diff --git a/src/platforms/hosted/bmp_hosted.h b/src/platforms/hosted/bmp_hosted.h index 3075d650df4..af3cc193f74 100644 --- a/src/platforms/hosted/bmp_hosted.h +++ b/src/platforms/hosted/bmp_hosted.h @@ -45,6 +45,8 @@ #define TRANSFER_IS_DONE (1U << 0U) #define TRANSFER_HAS_ERROR (1U << 1U) +#define BMDA_USB_NO_TIMEOUT 0 + typedef struct transfer_ctx { volatile size_t flags; } transfer_ctx_s; @@ -99,7 +101,8 @@ void libusb_exit_function(bmp_info_s *info); #if HOSTED_BMP_ONLY == 1 bool device_is_bmp_gdb_port(const char *device); #else -int bmda_usb_transfer(usb_link_s *link, const void *tx_buffer, size_t tx_len, void *rx_buffer, size_t rx_len); +int bmda_usb_transfer( + usb_link_s *link, const void *tx_buffer, size_t tx_len, void *rx_buffer, size_t rx_len, uint16_t timeout); #endif #endif /* PLATFORMS_HOSTED_BMP_HOSTED_H */ diff --git a/src/platforms/hosted/bmp_libusb.c b/src/platforms/hosted/bmp_libusb.c index 04fffe467cf..25d358d2d3c 100644 --- a/src/platforms/hosted/bmp_libusb.c +++ b/src/platforms/hosted/bmp_libusb.c @@ -569,7 +569,8 @@ int find_debuggers(bmda_cli_options_s *cl_opts, bmp_info_s *info) * sent/received may be less (per libusb's documentation). If used, rx_buffer must be * suitably intialised up front to avoid UB reads when accessed. */ -int bmda_usb_transfer(usb_link_s *link, const void *tx_buffer, size_t tx_len, void *rx_buffer, size_t rx_len) +int bmda_usb_transfer( + usb_link_s *link, const void *tx_buffer, size_t tx_len, void *rx_buffer, size_t rx_len, uint16_t timeout) { /* If there's data to send */ if (tx_len) { @@ -583,8 +584,8 @@ int bmda_usb_transfer(usb_link_s *link, const void *tx_buffer, size_t tx_len, vo DEBUG_WIRE("\n"); /* Perform the transfer */ - const int result = - libusb_bulk_transfer(link->device_handle, link->ep_tx | LIBUSB_ENDPOINT_OUT, tx_data, (int)tx_len, NULL, 0); + const int result = libusb_bulk_transfer( + link->device_handle, link->ep_tx | LIBUSB_ENDPOINT_OUT, tx_data, (int)tx_len, NULL, timeout); /* Then decode the result value - if its anything other than LIBUSB_SUCCESS, something went horribly wrong */ if (result != LIBUSB_SUCCESS) { DEBUG_ERROR( @@ -600,7 +601,7 @@ int bmda_usb_transfer(usb_link_s *link, const void *tx_buffer, size_t tx_len, vo int rx_bytes = 0; /* Perform the transfer */ const int result = libusb_bulk_transfer( - link->device_handle, link->ep_rx | LIBUSB_ENDPOINT_IN, rx_data, (int)rx_len, &rx_bytes, 0); + link->device_handle, link->ep_rx | LIBUSB_ENDPOINT_IN, rx_data, (int)rx_len, &rx_bytes, timeout); /* Then decode the result value - if its anything other than LIBUSB_SUCCESS, something went horribly wrong */ if (result != LIBUSB_SUCCESS) { DEBUG_ERROR( diff --git a/src/platforms/hosted/jlink.c b/src/platforms/hosted/jlink.c index 90906dce5d8..d99c15ff432 100644 --- a/src/platforms/hosted/jlink.c +++ b/src/platforms/hosted/jlink.c @@ -4,6 +4,7 @@ * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * Copyright (C) 2022-2023 1BitSquared * Modified by Rachel Mant + * Modified by Rafael Silva * * 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 @@ -42,41 +43,61 @@ #include "cli.h" -#define USB_VID_SEGGER 0x1366U +typedef struct jlink { + char fw_version[256U]; /* Firmware version string */ + uint32_t hw_version; /* Hardware version */ + uint32_t capabilities; /* Bitfield of supported capabilities */ + uint32_t available_interfaces; /* Bitfield of available interfaces */ -#define USB_PID_SEGGER_0101 0x0101U -#define USB_PID_SEGGER_0105 0x0105U -#define USB_PID_SEGGER_1015 0x1015U -#define USB_PID_SEGGER_1020 0x1020U + struct jlink_interface_frequency { + uint32_t base; /* Base frequency of the interface */ + uint16_t min_divisor; /* Minimum divisor for the interface */ + uint16_t current_divisor; /* Current divisor for the interface */ + } interface_frequency[JLINK_INTERFACE_MAX]; +} jlink_s; -static uint32_t jlink_caps; -static uint32_t jlink_freq_khz; -static uint16_t jlink_min_divisor; -static uint16_t jlink_current_divisor; -uint8_t jlink_interfaces; +jlink_s jlink; -int jlink_simple_query(const uint8_t command, void *const rx_buffer, const size_t rx_len) +/* J-Link USB protocol functions */ + +bool jlink_simple_query(const uint8_t command, void *const rx_buffer, const size_t rx_len) +{ + return bmda_usb_transfer(info.usb_link, &command, sizeof(command), rx_buffer, rx_len, JLINK_USB_TIMEOUT) >= 0; +} + +bool jlink_simple_request_8(const uint8_t command, const uint8_t operation, void *const rx_buffer, const size_t rx_len) +{ + const uint8_t request[2U] = {command, operation}; + return bmda_usb_transfer(info.usb_link, request, sizeof(request), rx_buffer, rx_len, JLINK_USB_TIMEOUT) >= 0; +} + +bool jlink_simple_request_16( + const uint8_t command, const uint16_t operation, void *const rx_buffer, const size_t rx_len) { - return bmda_usb_transfer(info.usb_link, &command, sizeof(command), rx_buffer, rx_len); + uint8_t request[3U] = {command}; + write_le2(request, 1U, operation); + return bmda_usb_transfer(info.usb_link, request, sizeof(request), rx_buffer, rx_len, JLINK_USB_TIMEOUT) >= 0; } -int jlink_simple_request(const uint8_t command, const uint8_t operation, void *const rx_buffer, const size_t rx_len) +bool jlink_simple_request_32( + const uint8_t command, const uint32_t operation, void *const rx_buffer, const size_t rx_len) { - const uint8_t request[2] = {command, operation}; - return bmda_usb_transfer(info.usb_link, request, sizeof(request), rx_buffer, rx_len); + uint8_t request[5U] = {command}; + write_le4(request, 1U, operation); + return bmda_usb_transfer(info.usb_link, request, sizeof(request), rx_buffer, rx_len, JLINK_USB_TIMEOUT) >= 0; } /* - * This runs JLINK_CMD_IO_TRANSACT transactions, these have the following format: - * ╭─────────┬─────────┬───────────────┬─────────╮ - * │ 0 │ 1 │ 2 │ 3 │ - * ├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ - * │ Command │ Align │ Cycle count │ - * ├─────────┼─────────┼───────────────┼─────────┤ - * │ 4 │ … │ 4 + tms_bytes │ … │ - * ├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤ - * │ TMS data bytes… │ TDI data bytes… │ - * ╰─────────┴─────────┴───────────────┴─────────╯ + * This runs JLINK_CMD_IO_TRANSACTION transactions, these have the following format: + * ┌─────────┬─────────┬───────────────┬───────┐ + * │ 0 │ 1 │ 2 │ 3 │ + * ├╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┴╌╌╌╌╌╌╌┤ + * │ Command │ Align │ Cycle count │ + * ├─────────┼─────────┼───────────────┬───────┤ + * │ 4 │ ... │ 4 + tms_bytes │ ... │ + * ├╌╌╌╌╌╌╌╌╌┴╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┴╌╌╌╌╌╌╌┤ + * │ TMS data bytes... │ TDI data bytes... │ + * └───────────────────┴───────────────────────┘ * where the byte counts for each of TDI and TMS are defined by: * count = ⌈cycle_count / 8⌉ * @@ -84,6 +105,9 @@ int jlink_simple_request(const uint8_t command, const uint8_t operation, void *c * * In SWD mode, the `tms` buffer represents direction states and * the `tdi` buffer represents SWDIO data to send to the device + * + * RM08001 Reference manual for J-Link USB Protocol + * §5.5.12 EMU_CMD_HW_JTAG3 */ bool jlink_transfer(const uint16_t clock_cycles, const uint8_t *const tms, const uint8_t *const tdi, uint8_t *const tdo) { @@ -101,7 +125,7 @@ bool jlink_transfer(const uint16_t clock_cycles, const uint8_t *const tms, const uint8_t buffer[1028U] = {0}; /* The first 4 bytes define the parameters of the transaction, so map the transfer structure there */ jlink_io_transact_s *header = (jlink_io_transact_s *)buffer; - header->command = JLINK_CMD_IO_TRANSACT; + header->command = JLINK_CMD_IO_TRANSACTION; write_le2(header->clock_cycles, 0, clock_cycles); /* Copy in the TMS state values to transmit (if present) */ if (tms) @@ -110,10 +134,10 @@ bool jlink_transfer(const uint16_t clock_cycles, const uint8_t *const tms, const if (tdi) memcpy(buffer + 4U + byte_count, tdi, byte_count); /* Send the resulting transaction and try to read back the response data */ - if (bmda_usb_transfer(info.usb_link, buffer, sizeof(jlink_io_transact_s) + (byte_count * 2U), buffer, byte_count) < - 0 || + if (bmda_usb_transfer( + info.usb_link, buffer, sizeof(*header) + (byte_count * 2U), buffer, byte_count, JLINK_USB_TIMEOUT) < 0 || /* Try to read back the transaction return code */ - bmda_usb_transfer(info.usb_link, NULL, 0, buffer + byte_count, 1U) < 0) + bmda_usb_transfer(info.usb_link, NULL, 0, buffer + byte_count, 1U, JLINK_USB_TIMEOUT) < 0) return false; /* Copy out the response into the TDO buffer (if present) */ if (tdo) @@ -136,7 +160,7 @@ bool jlink_transfer_fixed_tms( if (byte_count > 512U) return false; /* Set up the buffer for TMS */ - uint8_t tms[512] = {0}; + uint8_t tms[512U] = {0}; /* Figure out the position of the final bit in the sequence */ const size_t cycles = clock_cycles - 1U; const size_t final_byte = cycles >> 3U; @@ -151,7 +175,7 @@ bool jlink_transfer_swd( const uint16_t clock_cycles, const jlink_swd_dir_e direction, const uint8_t *const data_in, uint8_t *const data_out) { /* Define a buffer to hold the request direction information */ - uint8_t dir[8] = {0}; + uint8_t dir[8U] = {0}; /* Fill the direction buffer appropriately for the requested transfer direction */ memset(dir, direction == JLINK_SWD_IN ? 0x00U : 0xffU, sizeof(dir)); /* Run the resulting transfer */ @@ -159,83 +183,16 @@ bool jlink_transfer_swd( return jlink_transfer(clock_cycles, dir, data_in, data_out); } -static bool jlink_print_version(void) -{ - uint8_t len_str[2]; - if (jlink_simple_query(JLINK_CMD_GET_VERSION, len_str, sizeof(len_str)) < 0) - return false; - uint8_t version[0x70]; - bmda_usb_transfer(info.usb_link, NULL, 0, version, sizeof(version)); - version[0x6f] = '\0'; - DEBUG_INFO("%s\n", version); - return true; -} - -static bool jlink_query_caps(void) -{ - uint8_t caps[4]; - if (jlink_simple_query(JLINK_CMD_GET_CAPABILITIES, caps, sizeof(caps)) < 0) - return false; - jlink_caps = read_le4(caps, 0); - DEBUG_INFO("Caps %" PRIx32 "\n", jlink_caps); - - if (jlink_caps & JLINK_CAP_GET_HW_VERSION) { - uint8_t version[4]; - if (jlink_simple_query(JLINK_CMD_GET_ADAPTOR_VERSION, version, sizeof(version)) < 0) - return false; - DEBUG_INFO("HW: Type %u, Major %u, Minor %u, Rev %u\n", version[3], version[2], version[1], version[0]); - } - return true; -} - -static bool jlink_query_speed(void) -{ - uint8_t data[6]; - if (jlink_simple_query(JLINK_CMD_GET_ADAPTOR_FREQS, data, sizeof(data)) < 0) - return false; - jlink_freq_khz = read_le4(data, 0) / 1000U; - jlink_min_divisor = read_le2(data, 4); - DEBUG_INFO("Emulator speed %ukHz, minimum divisor %u%s\n", jlink_freq_khz, jlink_min_divisor, - (jlink_caps & JLINK_CAP_GET_SPEEDS) ? "" : ", fixed"); - return true; -} - -static bool jlink_print_interfaces(void) -{ - uint8_t active_if[4]; - uint8_t available_ifs[4]; - - if (jlink_simple_request(JLINK_CMD_TARGET_IF, JLINK_IF_GET_ACTIVE, active_if, sizeof(active_if)) < 0 || - jlink_simple_request(JLINK_CMD_TARGET_IF, JLINK_IF_GET_AVAILABLE, available_ifs, sizeof(available_ifs)) < 0) - return false; - ++active_if[0]; - jlink_interfaces = available_ifs[0]; - - if (active_if[0] == JLINK_IF_SWD) - DEBUG_INFO("SWD active"); - else if (active_if[0] == JLINK_IF_JTAG) - DEBUG_INFO("JTAG active"); - else - DEBUG_INFO("No interfaces active"); - - const uint8_t other_interface = available_ifs[0] - active_if[0]; - if (other_interface) - DEBUG_INFO(", %s available\n", other_interface == JLINK_IF_SWD ? "SWD" : "JTAG"); - else - DEBUG_INFO(", %s not available\n", active_if[0] + 1U == JLINK_IF_SWD ? "JTAG" : "SWD"); - return true; -} - -static bool jlink_info(void) -{ - return jlink_print_version() && jlink_query_caps() && jlink_query_speed() && jlink_print_interfaces(); -} - /* * Try to claim the debugging interface of a J-Link adaptor. * On success this copies the endpoint addresses identified into the * usb_link_s sub-structure of bmp_info_s (info.usb_link) for later use. * Returns true for success, false for failure. + * + * Note: Newer J-Links use 2 bulk endpoints, one for "IN" (EP1) and one + * for "OUT" (EP2) communication whereas old J-Links (V3, V4) only use + * one endpoint (EP1) for "IN" and "OUT" communication. + * Presently we only support the newer J-Links with 2 bulk endpoints. */ static bool jlink_claim_interface(void) { @@ -277,6 +234,320 @@ static bool jlink_claim_interface(void) return true; } +/* J-Link command functions and utils */ + +static char *jlink_hw_type_to_string(const uint8_t hw_type) +{ + switch (hw_type) { + case JLINK_HARDWARE_VERSION_TYPE_JLINK: + return "J-Link"; + case JLINK_HARDWARE_VERSION_TYPE_JTRACE: + return "J-Trace"; + case JLINK_HARDWARE_VERSION_TYPE_FLASHER: + return "Flasher"; + case JLINK_HARDWARE_VERSION_TYPE_JLINKPRO: + return "J-Link Pro"; + default: + return "Unknown"; + } +} + +static char *jlink_interface_to_string(const uint8_t interface) +{ + switch (interface) { + case JLINK_INTERFACE_JTAG: + return "JTAG"; + case JLINK_INTERFACE_SWD: + return "SWD"; + case JLINK_INTERFACE_BDM3: + return "BDM3"; + case JLINK_INTERFACE_FINE: + return "FINE"; + case JLINK_INTERFACE_2W_JTAG_PIC32: + return "PIC32 2-wire JTAG"; + case JLINK_INTERFACE_SPI: + return "SPI"; + case JLINK_INTERFACE_C2: + return "C2"; + case JLINK_INTERFACE_CJTAG: + return "cJTAG"; + default: + return "Unknown"; + } +} + +static bool jlink_get_version(void) +{ + uint8_t buffer[4U]; + + /* Read the firmware version, replies with a 2 byte length packet followed by the version string packet */ + if (!jlink_simple_query(JLINK_CMD_INFO_GET_FIRMWARE_VERSION, buffer, 2U)) + return false; + + /* Verify the version string fits in the buffer (expected value is 0x70) */ + const uint16_t version_length = read_le2(buffer, 0); + if (version_length > sizeof(jlink.fw_version)) + return false; + + /* Read vesion string directly into jlink.version */ + bmda_usb_transfer(info.usb_link, NULL, 0, jlink.fw_version, version_length, JLINK_USB_TIMEOUT); + jlink.fw_version[version_length - 1U] = '\0'; /* Ensure null termination */ + + DEBUG_INFO("Firmware version: %s\n", jlink.fw_version); + + /* Read the hardware version if supported */ + if (jlink.capabilities & JLINK_CAPABILITY_HARDWARE_VERSION) { + if (!jlink_simple_query(JLINK_CMD_INFO_GET_HARDWARE_VERSION, buffer, 4U)) + return false; + + jlink.hw_version = read_le4(buffer, 0); + + DEBUG_INFO("Hardware Version: %s V%u.%u.%u\n", + jlink_hw_type_to_string(JLINK_HARDWARE_VERSION_TYPE(jlink.hw_version)), + JLINK_HARDWARE_VERSION_MAJOR(jlink.hw_version), JLINK_HARDWARE_VERSION_MINOR(jlink.hw_version), + JLINK_HARDWARE_VERSION_REVISION(jlink.hw_version)); + } + + return true; +} + +static bool jlink_get_capabilities(void) +{ + uint8_t buffer[4U]; + if (!jlink_simple_query(JLINK_CMD_INFO_GET_PROBE_CAPABILITIES, buffer, sizeof(buffer))) + return false; + + jlink.capabilities = read_le4(buffer, 0); + DEBUG_INFO("Capabilities: 0x%08" PRIx32 "\n", jlink.capabilities); + + return true; +} + +static inline bool jlink_interface_available(const uint8_t interface) +{ + return jlink.available_interfaces & (1U << interface); +} + +static uint8_t jlink_selected_interface(void) +{ + uint8_t buffer[4U]; + if (!jlink_simple_request_8(JLINK_CMD_INTERFACE_GET, JLINK_INTERFACE_GET_CURRENT, buffer, sizeof(buffer))) + return UINT8_MAX; /* Invalid interface, max value is 31 */ + + /* The max value of interface is 31, so we can use the first byte of the 32 bit response directly */ + return buffer[0]; +} + +bool jlink_select_interface(const uint8_t interface) +{ + if (!jlink_interface_available(interface)) { + DEBUG_ERROR("Interface [%u] %s is not available\n", interface, jlink_interface_to_string(interface)); + return false; + } + + /* If the requested interface is already selected, we're done */ + if (jlink_selected_interface() == interface) + return true; + + /* Select the requested interface */ + uint8_t buffer[4U]; + if (!jlink_simple_request_8(JLINK_CMD_INTERFACE_SET_SELECTED, interface, buffer, sizeof(buffer))) + return false; + + /* Give the J-Link some time to switch interfaces */ + platform_delay(10U); + return true; +} + +static bool jlink_get_interfaces(void) +{ + uint8_t buffer[4U]; + if (!jlink_simple_request_8(JLINK_CMD_INTERFACE_GET, JLINK_INTERFACE_GET_AVAILABLE, buffer, sizeof(buffer))) + return false; + + /* available_interfaces is a 32bit bitfield/mask */ + jlink.available_interfaces = read_le4(buffer, 0); + + /* Print the available interfaces, marking the selected one, and unsuported ones */ + const uint8_t selected_interface = jlink_selected_interface(); + DEBUG_INFO("Available interfaces: \n"); + for (size_t i = 0; i < JLINK_INTERFACE_MAX; i++) { + if (jlink_interface_available(i)) { + const bool is_current = i == selected_interface; + const bool is_bmda_supported = i == JLINK_INTERFACE_SWD || i == JLINK_INTERFACE_JTAG; + + DEBUG_INFO("\t%zu: %s%c %s\n", i, jlink_interface_to_string(i), is_current ? '*' : ' ', + is_bmda_supported ? "" : "(Not supported)"); + } + } + + return true; +} + +static bool jlink_get_interface_frequency(const uint8_t interface) +{ + if (!(jlink.capabilities & JLINK_CAPABILITY_INTERFACE_FREQUENCY)) { + DEBUG_WARN("J-Link does not support interface frequency commands\n"); + return false; + } + + /* If the requested interface is invalid, bail out */ + if (!jlink_interface_available(interface)) + return false; + + /* If the base frequency is non-zero, we've already read the frequency info for the requested interface and can skip the query */ + if (jlink.interface_frequency[interface].base != 0U) + return true; + + /* Get the selected interface */ + const uint8_t selected_interface = jlink_selected_interface(); + + if (selected_interface != interface) { + /* If the selected interface doesn't match the requested interface, select it, let's hope this doesn't mess something up elsewhere */ + DEBUG_WARN("Trying to get frequency for interface %s but it is not selected, selecting it\n", + jlink_interface_to_string(interface)); + + /* select the requested interface */ + if (!jlink_select_interface(interface)) + return false; + } + + /* Get the frequency info for the selected interface */ + uint8_t buffer[6U]; + if (!jlink_simple_query(JLINK_CMD_INTERFACE_GET_BASE_FREQUENCY, buffer, sizeof(buffer))) + return false; + + struct jlink_interface_frequency *const interface_frequency = &jlink.interface_frequency[interface]; + + interface_frequency->base = read_le4(buffer, JLINK_INTERFACE_BASE_FREQUENCY_OFFSET); + interface_frequency->min_divisor = read_le2(buffer, JLINK_INTERFACE_MIN_DIV_OFFSET); + + /* This is an assumption, if the J-Link was configured before we started, this may not be true, but we have no way to know */ + interface_frequency->current_divisor = interface_frequency->min_divisor; + + DEBUG_INFO("%s interface frequency:\n\tBase frequency: %uHz\n\tMinimum divisor: %u\n", + jlink_interface_to_string(interface), interface_frequency->base, interface_frequency->min_divisor); + +#if 0 + /* + * Restoring the selected interface seemed to cause issues sometimes (unsure if culprit) + * so we don't do it for now, it didn't seem to be necessary, included in case it proves to be necessary later + */ + if (selected_interface != interface) { + /* If the selected interface didn't match the requested interface, restore the selected interface */ + DEBUG_WARN("Restoring selected interface to %s\n", jlink_interface_to_string(selected_interface)); + + /* select the requested interface, we don't consider this a critical failure, as we got what we wanted */ + if (!jlink_select_interface(selected_interface)) + DEBUG_ERROR("Failed to restore selected interface to %s\n", jlink_interface_to_string(selected_interface)); + } +#endif + + return true; +} + +static bool jlink_set_interface_frequency(const uint8_t interface, const uint32_t frequency) +{ + if (!(jlink.capabilities & JLINK_CAPABILITY_INTERFACE_FREQUENCY)) { + DEBUG_WARN("J-Link does not support interface frequency command\n"); + return false; + } + + /* Get the selected interface */ + const uint8_t selected_interface = jlink_selected_interface(); + + if (selected_interface != interface) { + /* If the selected interface doesn't match the requested interface, select it, let's hope this doesn't mess something up elsewhere */ + DEBUG_WARN("Trying to set frequency for interface %s but it is not selected, selecting it\n", + jlink_interface_to_string(interface)); + + /* select the requested interface */ + if (!jlink_select_interface(interface)) + return false; + } + + /* Ensure we have the frequency info for the selected interface */ + if (!jlink_get_interface_frequency(interface)) + return false; + + struct jlink_interface_frequency *const interface_frequency = &jlink.interface_frequency[interface]; + + /* Find the divisor that gets us closest to the requested frequency */ + uint16_t divisor = (interface_frequency->base + frequency - 1U) / frequency; + + /* Bound the divisor to the min divisor */ + if (divisor < interface_frequency->min_divisor) + divisor = interface_frequency->min_divisor; + + /* Get the approximate frequency we'll actually be running at, convert to kHz in the process */ + const uint16_t frequency_khz = (interface_frequency->base / interface_frequency->current_divisor) / 1000U; + + if (!jlink_simple_request_16(JLINK_CMD_INTERFACE_SET_FREQUENCY_KHZ, frequency_khz, NULL, 0)) + return false; + + /* Update the current divisor for frequency calculations */ + interface_frequency->current_divisor = divisor; + +#if 0 + /* + * Restoring the selected interface seemed to cause issues sometimes (unsure if culprit) + * so we don't do it for now, it didn't seem to be necessary, included in case it proves to be necessary later + */ + if (selected_interface != interface) { + /* If the selected interface didn't match the requested interface, restore the selected interface */ + DEBUG_WARN("Restoring selected interface to %s\n", jlink_interface_to_string(selected_interface)); + + /* select the requested interface, we don't consider this a critical failure, as we got what we wanted */ + if (!jlink_select_interface(selected_interface)) + DEBUG_ERROR("Failed to restore selected interface to %s\n", jlink_interface_to_string(selected_interface)); + } +#endif + + return true; +} + +static uint16_t jlink_target_voltage(void) +{ + uint8_t buffer[8U]; + if (!jlink_simple_query(JLINK_CMD_SIGNAL_GET_STATE, buffer, sizeof(buffer))) + return UINT16_MAX; + + return read_le2(buffer, JLINK_SIGNAL_STATE_VOLTAGE_OFFSET); +} + +static bool jlink_kickstart_power(void) +{ + if (!(jlink.capabilities & JLINK_CAPABILITY_POWER_STATE)) { + if (jlink.capabilities & JLINK_CAPABILITY_KICKSTART_POWER) + DEBUG_ERROR("J-Link does not support JLINK_CMD_POWER_GET_STATE command, but does support kickstart power" + ", this is unexpected\n"); + return false; + } + + uint8_t buffer[4U]; + if (!jlink_simple_request_32( + JLINK_CMD_POWER_GET_STATE, JLINK_POWER_STATE_KICKSTART_ENABLED_MASK, buffer, sizeof(buffer))) + return false; + + /* The result is a single bit, so we can use the first byte of the 32 bit response directly */ + return buffer[0] == 1U; +} + +static bool jlink_set_kickstart_power(const bool enable) +{ + /* + * Kickstart power is a 5V 300mA supply that can be used to power targets + * Exposed on pin 19 of the J-Link 20 pin connector + */ + + if (!(jlink.capabilities & JLINK_CAPABILITY_KICKSTART_POWER)) + return false; + + return jlink_simple_request_8(JLINK_CMD_POWER_SET_KICKSTART, enable ? JLINK_POWER_KICKSTART_ENABLE : 0, NULL, 0); +} + +/* BMDA interface functions */ + /* * Return true if single J-Link device connected or * serial given matches one of several J-Link devices. @@ -303,61 +574,77 @@ bool jlink_init(void) libusb_close(info.usb_link->device_handle); return false; } - jlink_info(); + if (!jlink_get_capabilities() || !jlink_get_version() || !jlink_get_interfaces()) { + DEBUG_ERROR("Failed to read J-Link information\n"); + libusb_release_interface(info.usb_link->device_handle, info.usb_link->interface); + libusb_close(info.usb_link->device_handle); + return false; + } + memcpy(info.version, jlink.fw_version, strlen(jlink.fw_version) + 1U); return true; } -const char *jlink_target_voltage(void) +uint32_t jlink_target_voltage_sense(void) { - static char result[7] = {'\0'}; + /* Convert from mV to dV (deci-Volt, i.e. tenths of a Volt) */ + return jlink_target_voltage() / 100U; +} - uint8_t data[8]; - if (jlink_simple_query(JLINK_CMD_GET_STATE, data, sizeof(data)) < 0) - return NULL; +const char *jlink_target_voltage_string(void) +{ + static char result[8U] = {'\0'}; - const uint16_t millivolts = read_le2(data, 0); - snprintf(result, sizeof(result), "%2u.%03u", millivolts / 1000U, millivolts % 1000U); + const uint16_t millivolts = jlink_target_voltage(); + if (millivolts == UINT16_MAX) + return "ERROR!"; + + snprintf(result, sizeof(result), "%2u.%03uV", millivolts / 1000U, millivolts % 1000U); return result; } void jlink_nrst_set_val(const bool assert) { - jlink_simple_query(assert ? JLINK_CMD_SET_RESET : JLINK_CMD_CLEAR_RESET, NULL, 0); - platform_delay(2); + jlink_simple_query(assert ? JLINK_CMD_SIGNAL_CLEAR_RESET : JLINK_CMD_SIGNAL_SET_RESET, NULL, 0); + platform_delay(2U); } bool jlink_nrst_get_val(void) { - uint8_t result[8]; - if (jlink_simple_query(JLINK_CMD_GET_STATE, result, sizeof(result)) < 0) + uint8_t result[8U]; + if (!jlink_simple_query(JLINK_CMD_SIGNAL_GET_STATE, result, sizeof(result))) return false; - return result[6] == 0; + + return result[JLINK_SIGNAL_STATE_TRES_OFFSET] == 0; } -bool jlink_set_frequency(const uint16_t frequency_khz) +void jlink_max_frequency_set(const uint32_t frequency) { - jlink_set_freq_s command = {JLINK_CMD_SET_FREQ}; - write_le2(command.frequency, 0, frequency_khz); - DEBUG_INFO("%s: %ukHz\n", __func__, frequency_khz); - return bmda_usb_transfer(info.usb_link, &command, sizeof(command), NULL, 0) >= 0; + const uint8_t bmda_interface = info.is_jtag ? JLINK_INTERFACE_JTAG : JLINK_INTERFACE_SWD; + + if (!jlink_set_interface_frequency(bmda_interface, frequency)) + DEBUG_ERROR("Failed to set J-Link %s interface frequency\n", jlink_interface_to_string(bmda_interface)); } -void jlink_max_frequency_set(const uint32_t freq) +uint32_t jlink_max_frequency_get(void) { - if (!(jlink_caps & JLINK_CAP_GET_SPEEDS) && !info.is_jtag) - return; - const uint16_t freq_khz = freq / 1000U; - const uint16_t divisor = (jlink_freq_khz + freq_khz - 1U) / freq_khz; - if (divisor > jlink_min_divisor) - jlink_current_divisor = divisor; - else - jlink_current_divisor = jlink_min_divisor; - jlink_set_frequency(jlink_freq_khz / jlink_current_divisor); + const uint8_t bmda_interface = info.is_jtag ? JLINK_INTERFACE_JTAG : JLINK_INTERFACE_SWD; + + /* Ensure we have the frequency info for the requested interface */ + if (!jlink_get_interface_frequency(bmda_interface)) { + DEBUG_ERROR("No frequency info available for interface %s\n", jlink_interface_to_string(bmda_interface)); + return FREQ_FIXED; + } + + struct jlink_interface_frequency *const interface_frequency = &jlink.interface_frequency[bmda_interface]; + return interface_frequency->base / interface_frequency->current_divisor; } -uint32_t jlink_max_frequency_get(void) +bool jlink_target_set_power(const bool power) +{ + return jlink_set_kickstart_power(power); +} + +bool jlink_target_get_power(void) { - if ((jlink_caps & JLINK_CAP_GET_SPEEDS) && info.is_jtag) - return (jlink_freq_khz * 1000U) / jlink_current_divisor; - return FREQ_FIXED; + return jlink_kickstart_power(); } diff --git a/src/platforms/hosted/jlink.h b/src/platforms/hosted/jlink.h index d76ad2a8934..0db282051e5 100644 --- a/src/platforms/hosted/jlink.h +++ b/src/platforms/hosted/jlink.h @@ -27,10 +27,13 @@ bool jlink_init(void); bool jlink_swd_init(adiv5_debug_port_s *dp); bool jlink_jtag_init(void); -const char *jlink_target_voltage(void); +uint32_t jlink_target_voltage_sense(void); +const char *jlink_target_voltage_string(void); void jlink_nrst_set_val(bool assert); bool jlink_nrst_get_val(void); -void jlink_max_frequency_set(uint32_t freq); +void jlink_max_frequency_set(uint32_t frequency); uint32_t jlink_max_frequency_get(void); +bool jlink_target_set_power(bool power); +bool jlink_target_get_power(void); #endif /* PLATFORMS_HOSTED_JLINK_H */ diff --git a/src/platforms/hosted/jlink_jtag.c b/src/platforms/hosted/jlink_jtag.c index 0e651ae6826..e2611f00d30 100644 --- a/src/platforms/hosted/jlink_jtag.c +++ b/src/platforms/hosted/jlink_jtag.c @@ -46,15 +46,13 @@ static const uint8_t jlink_switch_to_jtag_seq[9U] = {0xffU, 0xffU, 0xffU, 0xffU, bool jlink_jtag_init(void) { DEBUG_PROBE("-> jlink_jtag_init\n"); + /* Try to switch the adaptor into JTAG mode */ - uint8_t res[4]; - if (!(jlink_interfaces & JLINK_IF_JTAG) || - jlink_simple_request(JLINK_CMD_TARGET_IF, JLINK_IF_GET_AVAILABLE, res, sizeof(res)) < 0 || - !(res[0] & JLINK_IF_JTAG) || jlink_simple_request(JLINK_CMD_TARGET_IF, SELECT_IF_JTAG, res, sizeof(res)) < 0) { - DEBUG_ERROR("JTAG not available\n"); + if (!jlink_select_interface(JLINK_INTERFACE_JTAG)) { + DEBUG_ERROR("Failed to select JTAG interface\n"); return false; } - platform_delay(10); + /* Ensure we're in JTAG mode */ DEBUG_PROBE("%s: Switch to JTAG\n", __func__); if (!jlink_transfer(sizeof(jlink_switch_to_jtag_seq) * 8U, jlink_switch_to_jtag_seq, NULL, NULL)) { diff --git a/src/platforms/hosted/jlink_protocol.h b/src/platforms/hosted/jlink_protocol.h index 499075fe58e..4bf7182628e 100644 --- a/src/platforms/hosted/jlink_protocol.h +++ b/src/platforms/hosted/jlink_protocol.h @@ -3,6 +3,7 @@ * * Copyright (C) 2023 1BitSquared * Written by Rachel Mant + * Modified by Rafael Silva * * 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 @@ -25,41 +26,317 @@ #include #include -#define JLINK_CMD_GET_VERSION 0x01U -#define JLINK_CMD_SET_FREQ 0x05U -#define JLINK_CMD_GET_STATE 0x07U -#define JLINK_CMD_GET_ADAPTOR_FREQS 0xc0U -#define JLINK_CMD_TARGET_IF 0xc7U -#define JLINK_CMD_IO_TRANSACT 0xcfU -#define JLINK_CMD_SET_RESET 0xdcU -#define JLINK_CMD_CLEAR_RESET 0xddU -#define JLINK_CMD_GET_CAPABILITIES 0xe8U -#define JLINK_CMD_GET_CAPS_EXTENDED 0xedU -#define JLINK_CMD_GET_ADAPTOR_VERSION 0xf0U - -#define JLINK_IF_GET_ACTIVE 0xfeU -#define JLINK_IF_GET_AVAILABLE 0xffU - -#define JLINK_CAP_GET_SPEEDS (1U << 9U) -#define JLINK_CAP_GET_HW_VERSION (1U << 1U) -#define JLINK_IF_JTAG 1U -#define JLINK_IF_SWD 2U - -#define SELECT_IF_JTAG 0U -#define SELECT_IF_SWD 1U +/* + * This file contains the definitions for the J-Link USB Protocol as defined in the RM08001 Reference manual (Chapter §5) + * + * Overview + * The J-Link firmware uses several commands in a request reply topology to communicate with the host software + * Communication is always initiated by the host, which sends an 8 bit command to the probe followed by optional parameters + * USB bulk communication is used to transfer data between host and J-Link + * All data units larger than a single byte are transferred little endian, meaning least significant bytes are transferred first + * All USB operations use a 5 second timeout + * + * The commands have been reordered and renamed in the context of Black Magic Debug in an effort to make them more intuitive, consistent and easier to use. + * The mapping between the J-Link USB Protocol reference manual commands and the new Black Magic Debug commands is listed at the start of each command group below. + */ + +/* System information commands + * + * ┌────────────────────────────────────────────────┬──────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├────────────────────────────────────────────────┼──────────────────────────────────┤ + * │ JLINK_CMD_INFO_GET_FIRMWARE_VERSION │ §5.3.1 EMU_CMD_VERSION │ + * │ JLINK_CMD_INFO_GET_HARDWARE_VERSION │ §5.3.6 EMU_CMD_GET_HW_VERSION │ + * │ JLINK_CMD_INFO_GET_PROBE_CAPABILITIES │ §5.3.4 EMU_CMD_GET_CAPS │ + * │ JLINK_CMD_INFO_GET_PROBE_EXTENDED_CAPABILITIES │ §5.3.5 EMU_CMD_GET_CAPS_EX │ + * │ JLINK_CMD_INFO_GET_MAX_MEM_BLOCK │ §5.3.3 EMU_CMD_GET_MAX_MEM_BLOCK │ + * └────────────────────────────────────────────────┴──────────────────────────────────┘ + */ +#define JLINK_CMD_INFO_GET_FIRMWARE_VERSION 0x01U /* Get probe firmware version string */ +#define JLINK_CMD_INFO_GET_HARDWARE_VERSION 0xf0U /* Get probe hardware version */ +#define JLINK_CMD_INFO_GET_PROBE_CAPABILITIES 0xe8U /* Get probe capabilities */ +#define JLINK_CMD_INFO_GET_PROBE_EXTENDED_CAPABILITIES 0xedU /* Get probe extended capabilities */ +#define JLINK_CMD_INFO_GET_MAX_MEM_BLOCK 0xd4U /* Get the maximum memory blocksize */ + +/* Interface commands + * + * ┌────────────────────────────────────────┬────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├────────────────────────────────────────┼────────────────────────────────┤ + * │ JLINK_CMD_INTERFACE_GET_BASE_FREQUENCY │ §5.3.2 EMU_CMD_GET_SPEEDS │ + * │ JLINK_CMD_INTERFACE_SET_FREQUENCY_KHZ │ §5.5.2 EMU_CMD_SET_SPEED │ + * │ JLINK_CMD_INTERFACE_SET_SELECTED │ §5.5.3 EMU_CMD_SELECT_IF │ + * │ JLINK_CMD_INTERFACE_GET │ §5.5.3 EMU_CMD_SELECT_IF │ + * └────────────────────────────────────────┴────────────────────────────────┘ + */ +#define JLINK_CMD_INTERFACE_GET_BASE_FREQUENCY 0xc0U /* Get base frequency and minimum divider of selected interface */ +#define JLINK_CMD_INTERFACE_SET_FREQUENCY_KHZ 0x05U /* Sets the interface speed in kHz*/ +#define JLINK_CMD_INTERFACE_SET_SELECTED 0xc7U /* Select the probe interface */ +#define JLINK_CMD_INTERFACE_GET 0xc7U /* Get current selected interface or available interfaces */ + +/* Target power commands + * + * ┌───────────────────────────────┬────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├───────────────────────────────┼────────────────────────────────┤ + * │ JLINK_CMD_POWER_SET_KICKSTART │ §5.5.4 EMU_CMD_SET_KS_POWER │ + * │ JLINK_CMD_POWER_GET_STATE │ §5.4.2 EMU_CMD_GET_HW_INFO │ + * └───────────────────────────────┴────────────────────────────────┘ + */ +#define JLINK_CMD_POWER_SET_KICKSTART 0x08U /* Set KickStart power state on pin 19 (J-Link 20 pin connector) */ +#define JLINK_CMD_POWER_GET_STATE 0xc1U /* Get Kickstart power state and overcurrent timers */ + +/* Low level hardware commands + * + * ┌──────────────────────────────┬────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├──────────────────────────────┼────────────────────────────────┤ + * │ JLINK_CMD_SIGNAL_GET_STATE │ §5.4.1 EMU_CMD_GET_STATE │ + * │ JLINK_CMD_SIGNAL_CLEAR_RESET │ §5.6.4 EMU_CMD_HW_RESET0 │ + * │ JLINK_CMD_SIGNAL_SET_RESET │ §5.6.5 EMU_CMD_HW_RESET1 │ + * │ JLINK_CMD_SIGNAL_PULSE_RESET │ §5.6.1 EMU_CMD_RESET_TARGET │ + * │ JLINK_CMD_SIGNAL_CLEAR_TRST │ §5.5.15 EMU_CMD_HW_TRST0 │ + * │ JLINK_CMD_SIGNAL_SET_TRST │ §5.5.16 EMU_CMD_HW_TRST1 │ + * │ JLINK_CMD_SIGNAL_PULSE_TRST │ §5.5.1 EMU_CMD_RESET_TRST │ + * │ JLINK_CMD_SIGNAL_CLEAR_TMS │ §5.5.6 EMU_CMD_HW_TMS0 │ + * │ JLINK_CMD_SIGNAL_SET_TMS │ §5.5.7 EMU_CMD_HW_TMS1 │ + * │ JLINK_CMD_SIGNAL_CLEAR_TDI │ §5.5.8 EMU_CMD_HW_DATA0 │ + * │ JLINK_CMD_SIGNAL_SET_TDI │ §5.5.9 EMU_CMD_HW_DATA1 │ + * └──────────────────────────────┴────────────────────────────────┘ + */ +#define JLINK_CMD_SIGNAL_GET_STATE 0x07U /* Get target voltage and pin logic states */ +#define JLINK_CMD_SIGNAL_CLEAR_RESET 0xdcU /* Assert target reset */ +#define JLINK_CMD_SIGNAL_SET_RESET 0xddU /* Deassert target reset */ +#define JLINK_CMD_SIGNAL_PULSE_RESET 0x03U /* Assert target reset for 2ms */ +#define JLINK_CMD_SIGNAL_CLEAR_TRST 0xdeU /* Clear TRST */ +#define JLINK_CMD_SIGNAL_SET_TRST 0xdfU /* Set TRST */ +#define JLINK_CMD_SIGNAL_PULSE_TRST 0x02U /* Pulse TRST LOW for 2ms */ +#define JLINK_CMD_SIGNAL_CLEAR_TMS 0xc9U /* Clear TMS pin */ +#define JLINK_CMD_SIGNAL_SET_TMS 0xcaU /* Set TMS pin */ +#define JLINK_CMD_SIGNAL_CLEAR_TDI 0xcbU /* Clear TDI pin */ +#define JLINK_CMD_SIGNAL_SET_TDI 0xccU /* Set TDI pin */ + +/* Low level IO commands + * + * ┌────────────────────────────────────┬────────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├────────────────────────────────────┼────────────────────────────────────┤ + * │ JLINK_CMD_IO_PULSE_CLOCK │ §5.5.5 EMU_CMD_HW_CLOCK │ + * │ JLINK_CMD_IO_TRANSACTION │ §5.5.12 EMU_CMD_HW_JTAG3 │ + * │ JLINK_CMD_IO_WRITE │ §5.5.13 EMU_CMD_HW_JTAG_WRITE │ + * │ JLINK_CMD_IO_GET_WRITE_RESULT │ §5.5.14 EMU_CMD_HW_JTAG_GET_RESULT │ + * │ JLINK_CMD_IO_WRITE_DCC │ §5.5.17 EMU_CMD_WRITE_DCC │ + * │ JLINK_CMD_IO_TRANSACTION_OBSOLETE1 │ §5.5.10 EMU_CMD_HW_JTAG │ + * │ JLINK_CMD_IO_TRANSACTION_OBSOLETE2 │ §5.5.11 EMU_CMD_HW_JTAG2 │ + * └────────────────────────────────────┴────────────────────────────────────┘ + */ +#define JLINK_CMD_IO_PULSE_CLOCK 0xc8U /* Generate one clock cycle and return TDI value on falling edge */ +#define JLINK_CMD_IO_TRANSACTION 0xcfU /* Send data on TDI and TMS (SWDIO on SWD) and return TDO (SWDIO on SWD) */ +#define JLINK_CMD_IO_WRITE 0xd5U /* Same as IO_TRANSACTION w/o response data */ +#define JLINK_CMD_IO_GET_WRITE_RESULT 0xd6U /* Status of sticky error by CMD_IO_WRITE */ +#define JLINK_CMD_IO_WRITE_DCC 0xf1U /* Write to JTAG using DCC */ +#define JLINK_CMD_IO_TRANSACTION_OBSOLETE1 0xcdU /* Obsolete: Send data on TDI and TMS and return TDO */ +#define JLINK_CMD_IO_TRANSACTION_OBSOLETE2 0xceU /* Obsolete: Send data on TDI and TMS and return TDO */ + +/* High level target commands + * + * ┌─────────────────────────────────────────────┬────────────────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├─────────────────────────────────────────────┼────────────────────────────────────────────┤ + * │ JLINK_CMD_TARGET_RELEASE_RESET_HALT_RETRY │ §5.6.2 EMU_CMD_HW_RELEASE_RESET_STOP_EX │ + * │ JLINK_CMD_TARGET_RELEASE_RESET_HALT_TIMEOUT │ §5.6.3 EMU_CMD_HW_RELEASE_RESET_STOP_TIMED │ + * │ JLINK_CMD_TARGET_GET_CPU_CAPABILITIES │ §5.6.6 EMU_CMD_GET_CPU_CAPS │ + * │ JLINK_CMD_TARGET_EXECUTE_CPU_CMD │ §5.6.7 EMU_CMD_EXEC_CPU_CMD │ + * │ JLINK_CMD_TARGET_WRITE_MEMORY │ - EMU_CMD_WRITE_MEM │ + * │ JLINK_CMD_TARGET_READ_MEMORY │ - EMU_CMD_READ_MEM │ + * │ JLINK_CMD_TARGET_WRITE_MEMORY_ARM79 │ §5.6.8 EMU_CMD_WRITE_MEM_ARM79 │ + * │ JLINK_CMD_TARGET_READ_MEMORY_ARM79 │ §5.6.9 EMU_CMD_READ_MEM_ARM79 │ + * │ JLINK_CMD_TARGET_MEASURE_RTCK_REACTION_TIME │ §5.4.4 EMU_CMD_MEASURE_RTCK_REACT │ + * │ JLINK_CMD_TARGET_GET_CONNECTION_STATE │ §5.4.3 EMU_CMD_GET_COUNTERS │ + * └─────────────────────────────────────────────┴────────────────────────────────────────────┘ + */ +#define JLINK_CMD_TARGET_RELEASE_RESET_HALT_RETRY 0xd0U /* Resets the CPU and halts ASAP (fails after n retries) */ +#define JLINK_CMD_TARGET_RELEASE_RESET_HALT_TIMEOUT 0xd1U /* Resets the CPU and halts ASAP (fails after timeout) */ +#define JLINK_CMD_TARGET_GET_CPU_CAPABILITIES 0xe9U /* Get the capabilities of the target CPU */ +#define JLINK_CMD_TARGET_EXECUTE_CPU_CMD 0xeaU /* Executes target CPU functions */ +#define JLINK_CMD_TARGET_WRITE_MEMORY 0xf4U /* Write to target memory */ +#define JLINK_CMD_TARGET_READ_MEMORY 0xf5U /* Read from target memory */ +#define JLINK_CMD_TARGET_WRITE_MEMORY_ARM79 0xf7U /* Write to target memory on ARM 7/9 targets */ +#define JLINK_CMD_TARGET_READ_MEMORY_ARM79 0xf8U /* Read from target memory on ARM 7/9 targets */ +#define JLINK_CMD_TARGET_MEASURE_RTCK_REACTION_TIME 0xf6U /* Measure RTCK reaction time of the target device */ +#define JLINK_CMD_TARGET_GET_CONNECTION_STATE 0xc2U /* Get target connection timer counters */ + +/* Configuration commands + * + * ┌────────────────────────┬────────────────────────────────┐ + * │ BMDA J-Link command │ RM08001 J-Link USB Protocol RM │ + * ├────────────────────────┼────────────────────────────────┤ + * │ JLINK_CMD_CONFIG_READ │ §5.7.1 EMU_CMD_READ_CONFIG │ + * │ JLINK_CMD_CONFIG_WRITE │ §5.7.2 EMU_CMD_WRITE_CONFIG │ + * └────────────────────────┴────────────────────────────────┘ + */ +#define JLINK_CMD_CONFIG_READ 0xf2U /* Read the probe configuration */ +#define JLINK_CMD_CONFIG_WRITE 0xf3U /* Write the probe configuration */ + +/* + * The hardware version is returned as a 32 bit value with the following format: + * TTMMmmrr + * TT: Hardware type + * MM: Major version + * mm: Minor version + * rr: Revision + * + * Note for clarification of the reference manual: + * This is a 32 bit decimal value! not hex! (ugh... let's not question how long it took to figure that one out) +*/ +#define JLINK_HARDWARE_VERSION_TYPE(v) ((v / 1000000U) % 100U) /* Get hardware type from hardware version value */ +#define JLINK_HARDWARE_VERSION_MAJOR(v) ((v / 10000U) % 100U) /* Get major version from hardware version value */ +#define JLINK_HARDWARE_VERSION_MINOR(v) ((v / 100U) % 100U) /* Get minor version from hardware version value */ +#define JLINK_HARDWARE_VERSION_REVISION(v) (v % 100U) /* Get revision from hardware version value */ + +/* J-Link hardware version - JLINK_CMD_INFO_GET_HARDWARE_VERSION */ +#define JLINK_HARDWARE_VERSION_TYPE_JLINK 0U +#define JLINK_HARDWARE_VERSION_TYPE_JTRACE 1U +#define JLINK_HARDWARE_VERSION_TYPE_FLASHER 2U +#define JLINK_HARDWARE_VERSION_TYPE_JLINKPRO 3U + +/* J-Link capabilities - JLINK_CMD_INFO_GET_PROBE_CAPABILITIES + * + * ┌─────┬──────────────────────────────────────────┬────────────────────────────┐ + * │ Bit │ BMDA J-Link capability │ §5.3.4 EMU_CMD_GET_CAPS │ + * ├─────┼──────────────────────────────────────────┼────────────────────────────┤ + * │ 1 │ JLINK_CAPABILITY_RESERVED │ EMU_CAP_RESERVED │ + * │ 2 │ JLINK_CAPABILITY_HARDWARE_VERSION │ EMU_CAP_GET_HW_VERSION │ + * │ 3 │ JLINK_CAPABILITY_WRITE_DCC │ EMU_CAP_WRITE_DCC │ + * │ 4 │ JLINK_CAPABILITY_ADAPTIVE_CLOCKING │ EMU_CAP_ADAPTIVE_CLOCKING │ + * │ 5 │ JLINK_CAPABILITY_READ_CONFIG │ EMU_CAP_READ_CONFIG │ + * │ 6 │ JLINK_CAPABILITY_WRITE_CONFIG │ EMU_CAP_WRITE_CONFIG │ + * │ 7 │ JLINK_CAPABILITY_TRACE │ EMU_CAP_TRACE │ + * │ 8 │ JLINK_CAPABILITY_WRITE_MEMORY │ EMU_CAP_WRITE_MEM │ + * │ 9 │ JLINK_CAPABILITY_READ_MEMORY │ EMU_CAP_READ_MEM │ + * │ 10 │ JLINK_CAPABILITY_INTERFACE_FREQUENCY │ EMU_CAP_SPEED_INFO │ + * │ 11 │ JLINK_CAPABILITY_EXECUTE_CODE │ EMU_CAP_EXEC_CODE │ + * │ 12 │ JLINK_CAPABILITY_MAX_MEM_BLOCK │ EMU_CAP_GET_MAX_BLOCK_SIZE │ + * │ 13 │ JLINK_CAPABILITY_POWER_STATE │ EMU_CAP_GET_HW_INFO │ + * │ 14 │ JLINK_CAPABILITY_KICKSTART_POWER │ EMU_CAP_SET_KS_POWER │ + * │ 15 │ JLINK_CAPABILITY_HALT_TIMEOUT │ EMU_CAP_RESET_STOP_TIMED │ + * │ 15 │ JLINK_CAPABILITY_RESERVED2 │ - │ + * │ 16 │ JLINK_CAPABILITY_MEASURE_RTCK_REACT │ EMU_CAP_MEASURE_RTCK_REACT │ + * │ 17 │ JLINK_CAPABILITY_INTERFACES │ EMU_CAP_SELECT_IF │ + * │ 18 │ JLINK_CAPABILITY_MEMORY_ARM79 │ EMU_CAP_RW_MEM_ARM79 │ + * │ 19 │ JLINK_CAPABILITY_CONNECTION_STATE │ EMU_CAP_GET_COUNTERS │ + * │ 20 │ JLINK_CAPABILITY_READ_DCC │ EMU_CAP_READ_DCC │ + * │ 21 │ JLINK_CAPABILITY_TARGET_CPU_CAPABILITIES │ EMU_CAP_GET_CPU_CAPS │ + * │ 22 │ JLINK_CAPABILITY_TARGET_EXECUTE_CPU_CMD │ EMU_CAP_EXEC_CPU_CMD │ + * │ 23 │ JLINK_CAPABILITY_SWO │ EMU_CAP_SWO │ + * │ 24 │ JLINK_CAPABILITY_WRITE_DCC_EX │ EMU_CAP_WRITE_DCC_EX │ + * │ 25 │ JLINK_CAPABILITY_UPDATE_FIRMWARE_EX │ EMU_CAP_UPDATE_FIRMWARE_EX │ + * │ 26 │ JLINK_CAPABILITY_FILE_IO │ EMU_CAP_FILE_IO │ + * │ 27 │ JLINK_CAPABILITY_REGISTER │ EMU_CAP_REGISTER │ + * │ 28 │ JLINK_CAPABILITY_INDICATORS │ EMU_CAP_INDICATORS │ + * │ 29 │ JLINK_CAPABILITY_TEST_NET_SPEED │ EMU_CAP_TEST_NET_SPEED │ + * │ 30 │ JLINK_CAPABILITY_RAWTRACE │ EMU_CAP_RAWTRACE │ + * │ 31 │ JLINK_CAPABILITY_EXTENDED_CAPABILITIES │ EMU_CAP_EX_GET_CAPS_EX │ + * │ 32 │ JLINK_CAPABILITY_CMD_IO_WRITE │ EMU_CAP_EX_HW_JTAG_WRITE │ + * └─────┴──────────────────────────────────────────┴────────────────────────────┘ + * + * 'Undocumented' - The command/capability is not documented in the reference manual nor listed on this page + */ +#define JLINK_CAPABILITY_RESERVED (1U << 0U) /* Always 1 */ +#define JLINK_CAPABILITY_HARDWARE_VERSION (1U << 1U) /* Supports JLINK_CMD_INFO_GET_HARDWARE_VERSION */ +#define JLINK_CAPABILITY_WRITE_DCC (1U << 2U) /* Supports JLINK_CMD_IO_WRITE_DCC */ +#define JLINK_CAPABILITY_ADAPTIVE_CLOCKING (1U << 3U) /* Supports adaptive clocking */ +#define JLINK_CAPABILITY_READ_CONFIG (1U << 4U) /* Supports JLINK_CMD_CONFIG_READ */ +#define JLINK_CAPABILITY_WRITE_CONFIG (1U << 5U) /* Supports JLINK_CMD_CONFIG_WRITE */ +#define JLINK_CAPABILITY_TRACE (1U << 6U) /* Supports trace commands */ +#define JLINK_CAPABILITY_WRITE_MEMORY (1U << 7U) /* Supports JLINK_CMD_TARGET_WRITE_MEMORY */ +#define JLINK_CAPABILITY_READ_MEMORY (1U << 8U) /* Supports JLINK_CMD_TARGET_READ_MEMORY */ +#define JLINK_CAPABILITY_INTERFACE_FREQUENCY (1U << 9U) /* Supports JLINK_CMD_INTERFACE_GET_BASE_FREQUENCY */ +#define JLINK_CAPABILITY_EXECUTE_CODE (1U << 10U) /* Undocumented: Supports EMU_CMD_CODE_... commands */ +#define JLINK_CAPABILITY_MAX_MEM_BLOCK (1U << 11U) /* Supports JLINK_CMD_INFO_GET_MAX_MEM_BLOCK */ +#define JLINK_CAPABILITY_POWER_STATE (1U << 12U) /* Supports JLINK_CMD_POWER_GET_STATE */ +#define JLINK_CAPABILITY_KICKSTART_POWER (1U << 13U) /* Supports Kickstart power on pin 19 (J-Link 20 pin connector) */ +#define JLINK_CAPABILITY_HALT_TIMEOUT (1U << 14U) /* Supports JLINK_CMD_TARGET_RELEASE_RESET_HALT_TIMEOUT */ +#define JLINK_CAPABILITY_RESERVED2 (1U << 0U) /* 15 Unknown Reserved */ +#define JLINK_CAPABILITY_MEASURE_RTCK_REACT (1U << 16U) /* Supports JLINK_CMD_TARGET_MEASURE_RTCK_REACTION_TIME */ +#define JLINK_CAPABILITY_INTERFACES (1U << 17U) /* Supports JLINK_CMD_INTERFACE_GET/SET_SELECTED */ +#define JLINK_CAPABILITY_MEMORY_ARM79 (1U << 18U) /* Supports JLINK_CMD_TARGET_READ/WRITE_MEMORY_ARM79 */ +#define JLINK_CAPABILITY_CONNECTION_STATE (1U << 19U) /* Supports JLINK_CMD_TARGET_GET_CONNECTION_STATE */ +#define JLINK_CAPABILITY_READ_DCC (1U << 20U) /* Undocumented: Supports READ_DCC */ +#define JLINK_CAPABILITY_TARGET_CPU_CAPABILITIES (1U << 21U) /* Supports JLINK_CMD_TARGET_GET_CPU_CAPABILITIES */ +#define JLINK_CAPABILITY_TARGET_EXECUTE_CPU_CMD (1U << 22U) /* Supports JLINK_CMD_TARGET_EXECUTE_CPU_CMD */ +#define JLINK_CAPABILITY_SWO (1U << 23U) /* Supports SWO */ +#define JLINK_CAPABILITY_WRITE_DCC_EX (1U << 24U) /* Undocumented: Supports WRITE_DCC_EX */ +#define JLINK_CAPABILITY_UPDATE_FIRMWARE_EX (1U << 25U) /* Undocumented: Supports UPDATE_FIRMWARE_EX */ +#define JLINK_CAPABILITY_FILE_IO (1U << 26U) /* Undocumented: Supports FILE_IO */ +#define JLINK_CAPABILITY_REGISTER (1U << 27U) /* Undocumented: Supports REGISTER */ +#define JLINK_CAPABILITY_INDICATORS (1U << 28U) /* Undocumented: Supports INDICATORS */ +#define JLINK_CAPABILITY_TEST_NET_SPEED (1U << 29U) /* Undocumented: Supports TEST_NET_SPEED */ +#define JLINK_CAPABILITY_RAWTRACE (1U << 30U) /* Undocumented: Supports RAWTRACE */ +#define JLINK_CAPABILITY_EXTENDED_CAPABILITIES (1U << 31U) /* Supports extended capabilities */ +#define JLINK_CAPABILITY_CMD_IO_WRITE (1U << 32U) /* Supports JLINK_CMD_IO_WRITE */ + +/* Interface base frequency and min divider - JLINK_CMD_INTERFACE_GET_BASE_FREQUENCY */ +#define JLINK_INTERFACE_BASE_FREQUENCY_OFFSET 0U /* 32 bit value */ +#define JLINK_INTERFACE_MIN_DIV_OFFSET 4U /* 8 bit value */ + +/* Interface get - JLINK_CMD_INTERFACE_GET */ +#define JLINK_INTERFACE_GET_AVAILABLE 0xffU /* returns 32 bit bitfield of available interfaces */ +#define JLINK_INTERFACE_GET_CURRENT 0xfeU /* return currently selected interface number */ + +#define JLINK_INTERFACE_AVAILABLE(i) (1U << (i)) /* Convert interface number to bitfield bit */ + +/* Interfaces */ +#define JLINK_INTERFACE_MAX 32U +#define JLINK_INTERFACE_JTAG 0U +#define JLINK_INTERFACE_SWD 1U +/* The following interfaces were obtained from libjaylink, with no official documentation to back them up */ +#define JLINK_INTERFACE_BDM3 2U /* Background Debug Mode 3 (BDM3) */ +#define JLINK_INTERFACE_FINE 3U /* Renesas’ single-wire debug interface (FINE) */ +#define JLINK_INTERFACE_2W_JTAG_PIC32 4U /* 2-wire JTAG for PIC32 compliant devices */ +#define JLINK_INTERFACE_SPI 5U /* Serial Peripheral Interface (SPI) */ +#define JLINK_INTERFACE_C2 6U /* Silicon Labs 2-wire interface (C2) */ +#define JLINK_INTERFACE_CJTAG 7U /* Compact JTAG (cJTAG) */ + +/* Kickstart power - JLINK_CMD_POWER_SET_KICKSTART */ +#define JLINK_POWER_KICKSTART_ENABLE 0x01U /* Set Kickstart power on */ + +/* Power state - JLINK_CMD_POWER_GET_STATE */ +#define JLINK_POWER_STATE_KICKSTART_ENABLED_MASK (1U << 0U) /* Retrieves Kickstart power status */ +#define JLINK_POWER_STATE_OVERCURRENT_MASK (1U << 1U) /* Information about why the target power was switched off */ +#define JLINK_POWER_STATE_ITARGET_MASK (1U << 2U) /* Target consumption(mA) */ +#define JLINK_POWER_STATE_ITARGET_PEAK_MASK (1U << 3U) /* Peak target consumption(mA) */ +#define JLINK_POWER_STATE_ITARGET_PEAK_OPERATION_MASK (1U << 4U) /* Peak operation target consumption(mA) */ +#define JLINK_POWER_STATE_ITARGET_MAX_TIME_2MS_3A_MASK (1U << 10U) /* Time(ms) target consumption exceeded 3A */ +#define JLINK_POWER_STATE_ITARGET_MAX_TIME_10MS_1A_MASK (1U << 11U) /* Time(ms) target consumption exceeded 1A */ +#define JLINK_POWER_STATE_ITARGET_MAX_TIME_40MS_400MA_MASK (1U << 12U) /* Time(ms) target consumption exceeded 400MA */ +#define JLINK_POWER_STATE_VUSB_MASK (1U << 23U) /* USB voltage in mV */ + +#define JLINK_POWER_STATE_KICKSTART_ENABLED 0x1U /* Kickstart power is on */ +#define JLINK_POWER_STATE_OVERCURRENT_NORMAL 0x0U /* Everything is normal */ +#define JLINK_POWER_STATE_OVERCURRENT_2MS_3A 0x1U /* 2ms @ 3000mA */ +#define JLINK_POWER_STATE_OVERCURRENT_10MS_1A 0x2U /* 10ms @ 1000mA */ +#define JLINK_POWER_STATE_OVERCURRENT_40MS_400MA 0x3U /* 40ms @ 400mA */ + +/* Signal state - JLINK_CMD_SIGNAL_GET_STATE */ +#define JLINK_SIGNAL_STATE_VOLTAGE_OFFSET 0U /* 16 bit value */ +#define JLINK_SIGNAL_STATE_TCK_OFFSET 2U /* 1 bit value */ +#define JLINK_SIGNAL_STATE_TDI_OFFSET 3U /* 1 bit value */ +#define JLINK_SIGNAL_STATE_TDO_OFFSET 4U /* 1 bit value */ +#define JLINK_SIGNAL_STATE_TMS_OFFSET 5U /* 1 bit value */ +#define JLINK_SIGNAL_STATE_TRES_OFFSET 6U /* 1 bit value */ +#define JLINK_SIGNAL_STATE_TRST_OFFSET 7U /* 1 bit value */ + +/* J-Link USB protocol constants */ +#define JLINK_USB_TIMEOUT 5000U /* 5 seconds */ typedef enum jlink_swd_dir { JLINK_SWD_OUT, JLINK_SWD_IN, } jlink_swd_dir_e; -typedef struct jlink_set_freq { - uint8_t command; - uint8_t frequency[2]; -} jlink_set_freq_s; - typedef struct jlink_io_transact { - /* This must always be set to JLINK_CMD_IO_TRANSACT */ + /* This must always be set to JLINK_CMD_IO_TRANSACTION */ uint8_t command; /* This value exists for alignment purposes and must be 0 */ uint8_t reserved; @@ -67,13 +344,13 @@ typedef struct jlink_io_transact { uint8_t clock_cycles[2]; } jlink_io_transact_s; -extern uint8_t jlink_interfaces; - -int jlink_simple_query(uint8_t command, void *rx_buffer, size_t rx_len); -int jlink_simple_request(uint8_t command, uint8_t operation, void *rx_buffer, size_t rx_len); +bool jlink_simple_query(uint8_t command, void *rx_buffer, size_t rx_len); +bool jlink_simple_request_8(uint8_t command, uint8_t operation, void *rx_buffer, size_t rx_len); +bool jlink_simple_request_16(uint8_t command, uint16_t operation, void *rx_buffer, size_t rx_len); +bool jlink_simple_request_32(uint8_t command, uint32_t operation, void *rx_buffer, size_t rx_len); bool jlink_transfer(uint16_t clock_cycles, const uint8_t *tms, const uint8_t *tdi, uint8_t *tdo); bool jlink_transfer_fixed_tms(uint16_t clock_cycles, bool final_tms, const uint8_t *tdi, uint8_t *tdo); bool jlink_transfer_swd(uint16_t clock_cycles, jlink_swd_dir_e direction, const uint8_t *data_in, uint8_t *data_out); -bool jlink_set_frequency(uint16_t frequency_khz); +bool jlink_select_interface(const uint8_t interface); #endif /*PLATFORMS_HOSTED_JLINK_PROTOCOL_H*/ diff --git a/src/platforms/hosted/jlink_swd.c b/src/platforms/hosted/jlink_swd.c index d3edf590899..081fc002199 100644 --- a/src/platforms/hosted/jlink_swd.c +++ b/src/platforms/hosted/jlink_swd.c @@ -86,15 +86,12 @@ static uint32_t jlink_adiv5_raw_access(adiv5_debug_port_s *dp, uint8_t rnw, uint bool jlink_swd_init(adiv5_debug_port_s *dp) { DEBUG_PROBE("-> jlink_swd_init(%u)\n", dp->dev_index); + /* Try to switch the adaptor into SWD mode */ - uint8_t res[4]; - if (!(jlink_interfaces & JLINK_IF_SWD) || - jlink_simple_request(JLINK_CMD_TARGET_IF, JLINK_IF_GET_AVAILABLE, res, sizeof(res)) < 0 || - !(res[0] & JLINK_IF_SWD) || jlink_simple_request(JLINK_CMD_TARGET_IF, SELECT_IF_SWD, res, sizeof(res)) < 0) { - DEBUG_ERROR("SWD not available\n"); + if (!jlink_select_interface(JLINK_INTERFACE_SWD)) { + DEBUG_ERROR("Failed to select SWD interface\n"); return false; } - platform_delay(10); /* Set up the underlying SWD functions using the implementation below */ swd_proc.seq_in = jlink_swd_seq_in; diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 9f2ab5e8314..d222d86ac35 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -346,7 +346,7 @@ const char *platform_target_voltage(void) return ftdi_target_voltage(); case BMP_TYPE_JLINK: - return jlink_target_voltage(); + return jlink_target_voltage_string(); #endif default: @@ -470,18 +470,20 @@ uint32_t platform_max_frequency_get(void) } } -void platform_target_set_power(const bool power) +bool platform_target_set_power(const bool power) { switch (info.bmp_type) { case BMP_TYPE_BMP: - if (remote_target_set_power(power)) - DEBUG_INFO("Powering up device!\n"); - else - DEBUG_ERROR("Powering up device unimplemented or failed\n"); - break; + return remote_target_set_power(power); + +#if HOSTED_BMP_ONLY == 0 + case BMP_TYPE_JLINK: + return jlink_target_set_power(power); +#endif default: - break; + DEBUG_ERROR("Target power not available or not yet implemented\n"); + return false; } } @@ -491,6 +493,11 @@ bool platform_target_get_power(void) case BMP_TYPE_BMP: return remote_target_get_power(); +#if HOSTED_BMP_ONLY == 0 + case BMP_TYPE_JLINK: + return jlink_target_get_power(); +#endif + default: return false; } @@ -512,6 +519,12 @@ uint32_t platform_target_voltage_sense(void) break; } +#if HOSTED_BMP_ONLY == 0 + case BMP_TYPE_JLINK: + targetVoltage = jlink_target_voltage_sense(); + break; +#endif + default: break; } diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h index dde876bbbdb..4cf19fa2a03 100644 --- a/src/platforms/hosted/platform.h +++ b/src/platforms/hosted/platform.h @@ -76,6 +76,13 @@ void platform_buffer_flush(void); #define VENDOR_ID_ORBCODE 0x1209U #define PRODUCT_ID_ORBTRACE 0x3443U +/* + * All known Segger J-Link Product IDs for future reference: + * 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0107, 0x0108, + * 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, + * 0x1017, 0x1018, 0x1020, 0x1024, 0x1051, 0x1055, 0x1061 + */ + typedef enum bmp_type_e { BMP_TYPE_NONE = 0, BMP_TYPE_BMP, diff --git a/src/platforms/hosted/stlinkv2.c b/src/platforms/hosted/stlinkv2.c index c66460aafb7..91953602423 100644 --- a/src/platforms/hosted/stlinkv2.c +++ b/src/platforms/hosted/stlinkv2.c @@ -221,7 +221,7 @@ int stlink_send_recv_retry( int res; int first_res = STLINK_ERROR_OK; while (true) { - bmda_usb_transfer(info.usb_link, req_buffer, req_len, rx_buffer, rx_len); + bmda_usb_transfer(info.usb_link, req_buffer, req_len, rx_buffer, rx_len, BMDA_USB_NO_TIMEOUT); res = stlink_usb_error_check(rx_buffer, false); if (res == STLINK_ERROR_OK) return res; @@ -251,7 +251,7 @@ static int stlink_read_retry( uint32_t start = platform_time_ms(); int res; while (true) { - bmda_usb_transfer(info.usb_link, req_buffer, req_len, rx_buffer, rx_len); + bmda_usb_transfer(info.usb_link, req_buffer, req_len, rx_buffer, rx_len, BMDA_USB_NO_TIMEOUT); res = stlink_usb_get_rw_status(false); if (res == STLINK_ERROR_OK) return res; @@ -272,8 +272,8 @@ static int stlink_write_retry( int res; usb_link_s *link = info.usb_link; while (true) { - bmda_usb_transfer(link, req_buffer, req_len, NULL, 0); - bmda_usb_transfer(link, tx_buffer, tx_len, NULL, 0); + bmda_usb_transfer(link, req_buffer, req_len, NULL, 0, BMDA_USB_NO_TIMEOUT); + bmda_usb_transfer(link, tx_buffer, tx_len, NULL, 0, BMDA_USB_NO_TIMEOUT); res = stlink_usb_get_rw_status(false); if (res == STLINK_ERROR_OK) return res; @@ -292,7 +292,7 @@ int stlink_simple_query(const uint8_t command, const uint8_t operation, void *co .command = command, .operation = operation, }; - return bmda_usb_transfer(info.usb_link, &request, sizeof(request), rx_buffer, rx_len); + return bmda_usb_transfer(info.usb_link, &request, sizeof(request), rx_buffer, rx_len, BMDA_USB_NO_TIMEOUT); } int stlink_simple_request( @@ -303,7 +303,7 @@ int stlink_simple_request( .operation = operation, .param = param, }; - return bmda_usb_transfer(info.usb_link, &request, sizeof(request), rx_buffer, rx_len); + return bmda_usb_transfer(info.usb_link, &request, sizeof(request), rx_buffer, rx_len, BMDA_USB_NO_TIMEOUT); } /* @@ -730,7 +730,7 @@ static uint32_t stlink_reg_read(adiv5_access_port_s *const ap, const uint8_t reg .reg_num = reg_num, .apsel = ap->apsel, }; - bmda_usb_transfer(info.usb_link, &request, sizeof(request), data, sizeof(data)); + bmda_usb_transfer(info.usb_link, &request, sizeof(request), data, sizeof(data), BMDA_USB_NO_TIMEOUT); stlink_usb_error_check(data, true); const uint32_t result = read_le4(data, 0U); DEBUG_PROBE("%s: AP %u, reg %02u val 0x%08" PRIx32 "\n", __func__, ap->apsel, reg_num, result); @@ -747,7 +747,7 @@ static void stlink_reg_write(adiv5_access_port_s *const ap, const uint8_t reg_nu .apsel = ap->apsel, }; write_le4(request.value, 0U, value); - bmda_usb_transfer(info.usb_link, &request, sizeof(request), res, sizeof(res)); + bmda_usb_transfer(info.usb_link, &request, sizeof(request), res, sizeof(res), BMDA_USB_NO_TIMEOUT); DEBUG_PROBE("%s: AP %u, reg %02u val 0x%08" PRIx32 "\n", __func__, ap->apsel, reg_num, value); stlink_usb_error_check(res, true); } @@ -815,7 +815,7 @@ static void stlink_v2_set_frequency(const uint32_t freq) DEBUG_WARN("Divisor for %u.%03uMHz is %u\n", freq_mhz, freq_khz, stlink_v2_divisor); write_le2(request.divisor, 0U, stlink_v2_divisor); uint8_t data[2]; - bmda_usb_transfer(info.usb_link, &request, sizeof(request), data, sizeof(data)); + bmda_usb_transfer(info.usb_link, &request, sizeof(request), data, sizeof(data), BMDA_USB_NO_TIMEOUT); if (stlink_usb_error_check(data, false)) DEBUG_ERROR("Set frequency failed!\n"); } @@ -845,7 +845,7 @@ static void stlink_v3_set_frequency(const uint32_t freq) .mode = mode, }; write_le4(request.frequency, 0U, frequency); - bmda_usb_transfer(info.usb_link, &request, sizeof(request), data, 8); + bmda_usb_transfer(info.usb_link, &request, sizeof(request), data, 8U, BMDA_USB_NO_TIMEOUT); stlink_usb_error_check(data, true); stlink_v3_freq[mode] = frequency * 1000U; } diff --git a/src/platforms/native/platform.c b/src/platforms/native/platform.c index bc3a7a59a94..44c9cda80eb 100644 --- a/src/platforms/native/platform.c +++ b/src/platforms/native/platform.c @@ -272,10 +272,13 @@ bool platform_target_get_power(void) return false; } -void platform_target_set_power(const bool power) +bool platform_target_set_power(const bool power) { - if (platform_hwversion() > 0) - gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power); + if (platform_hwversion() <= 0) + return false; + + gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power); + return true; } static void adc_init(void) diff --git a/src/remote.c b/src/remote.c index 5a853984f87..9e1959e46bc 100644 --- a/src/remote.c +++ b/src/remote.c @@ -287,8 +287,8 @@ static void remote_packet_process_general(char *packet, const size_t packet_len) */ remote_respond(REMOTE_RESP_ERR, 0); } else { - platform_target_set_power(packet[2] == '1'); - remote_respond(REMOTE_RESP_OK, 0); + const bool result = platform_target_set_power(packet[2] == '1'); + remote_respond(result ? REMOTE_RESP_OK : REMOTE_RESP_ERR, 0); } #else remote_respond(REMOTE_RESP_NOTSUP, 0);