static void show_config(struct command_context *ctx) { command_print(ctx, "J-Link device configuration:"); show_config_usb_address(ctx); if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) show_config_target_power(ctx); if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { show_config_ip_address(ctx); show_config_mac_address(ctx); } }
static int jlink_quit(void) { int ret; if (trace_enabled) { ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror_name(ret)); } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { ret = jaylink_unregister(devh, &conn, connlist, NULL, NULL); if (ret < 0) LOG_ERROR("jaylink_unregister() failed: %s.", jaylink_strerror_name(ret)); } jaylink_close(devh); jaylink_exit(jayctx); return ERROR_OK; }
/* * Adjust the SWD transaction buffer size depending on the free device internal * memory. This ensures that the SWD transactions sent to the device do not * exceed the internal memory of the device. */ static bool adjust_swd_buffer_size(void) { int ret; uint32_t tmp; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) return true; ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s.", jaylink_strerror_name(ret)); return false; } if (tmp < 143) { LOG_ERROR("Not enough free device internal memory: %u bytes.", tmp); return false; } tmp = MIN(JLINK_TAP_BUFFER_SIZE, (tmp - 16) / 2); if (tmp != swd_buffer_size) { swd_buffer_size = tmp; LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes.", swd_buffer_size); } return true; }
static int jlink_register(void) { int ret; int i; bool handle_found; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) return ERROR_OK; ret = jaylink_register(devh, &conn, connlist, NULL, NULL); if (ret < 0) { LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror_name(ret)); return ERROR_FAIL; } handle_found = false; for (i = 0; i < ret; i++) { if (connlist[i].handle == conn.handle) { handle_found = true; break; } } if (!handle_found) { LOG_ERROR("Registration failed: maximum number of connections on the " "device reached."); return ERROR_FAIL; } return ERROR_OK; }
static int jlink_speed(int speed) { int ret; uint32_t freq; uint16_t divider; int max_speed; if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) { ret = jaylink_get_speeds(devh, &freq, ÷r); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_speeds() failed: %s.", jaylink_strerror_name(ret)); return ERROR_JTAG_DEVICE_ERROR; } freq = freq / 1000; max_speed = freq / divider; } else { max_speed = JLINK_MAX_SPEED; } if (!speed) { if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING)) { 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, max_speed); speed = max_speed; } ret = jaylink_set_speed(devh, speed); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_set_speed() failed: %s.", jaylink_strerror_name(ret)); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; }
static uint32_t calculate_trace_buffer_size(void) { int ret; uint32_t tmp; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) return 0; ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s.", jaylink_strerror_name(ret)); return ERROR_FAIL; } if (tmp > 0x3fff || tmp <= 0x600) tmp = tmp >> 1; else
static int select_interface(void) { int ret; uint32_t interfaces; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SELECT_TIF)) { if (iface != JAYLINK_TIF_JTAG) { LOG_ERROR("Device supports JTAG transport only."); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } ret = jaylink_get_available_interfaces(devh, &interfaces); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_available_interfaces() failed: %s.", jaylink_strerror_name(ret)); return ERROR_JTAG_INIT_FAILED; } if (!(interfaces & (1 << iface))) { LOG_ERROR("Selected transport is not supported by the device."); return ERROR_JTAG_INIT_FAILED; } ret = jaylink_select_interface(devh, iface); if (ret < 0) { LOG_ERROR("jaylink_select_interface() failed: %s.", jaylink_strerror_name(ret)); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; }
int jlink_spi_init(void) { char *arg; unsigned long speed = 0; register_shutdown(jlink_spi_shutdown, NULL); arg = extract_programmer_param("spispeed"); if (arg) { char *endptr; errno = 0; speed = strtoul(arg, &endptr, 10); if (*endptr != '\0' || errno != 0) { msg_perr("Invalid SPI speed specified: %s.\n", arg); free(arg); return 1; } if (speed < 1) { msg_perr("SPI speed must be at least 1 kHz.\n"); free(arg); return 1; } } free(arg); int ret; bool use_serial_number; uint32_t serial_number; arg = extract_programmer_param("serial"); if (arg) { if (!strlen(arg)) { msg_perr("Emptpy serial number specified.\n"); free(arg); return 1; } ret = jaylink_parse_serial_number(arg, &serial_number); if (ret == JAYLINK_ERR) { msg_perr("Invalid serial number specified: %s.\n", arg); free(arg); return 1; } if (ret != JAYLINK_OK) { msg_perr("jaylink_parse_serial_number() failed: %s.\n", jaylink_strerror(ret)); free(arg); return 1; } use_serial_number = true; } else { use_serial_number = false; } free(arg); reset_cs = true; arg = extract_programmer_param("cs"); if (arg) { if (!strcasecmp(arg, "reset")) { reset_cs = true; } else if (!strcasecmp(arg, "trst")) { reset_cs = false; } else { msg_perr("Invalid chip select pin specified: '%s'.\n", arg); free(arg); return 1; } } free(arg); if (reset_cs) msg_pdbg("Using RESET as chip select signal.\n"); else msg_pdbg("Using TRST as chip select signal.\n"); ret = jaylink_init(&jaylink_ctx); if (ret != JAYLINK_OK) { msg_perr("jaylink_init() failed: %s.\n", jaylink_strerror(ret)); return 1; } ret = jaylink_discovery_scan(jaylink_ctx, 0); if (ret != JAYLINK_OK) { msg_perr("jaylink_discover_scan() failed: %s.\n", jaylink_strerror(ret)); return 1; } struct jaylink_device **devs; ret = jaylink_get_devices(jaylink_ctx, &devs, NULL); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_devices() failed: %s.\n", jaylink_strerror(ret)); return 1; } if (!use_serial_number) msg_pdbg("No device selected, using first device.\n"); size_t i; struct jaylink_device *dev; bool device_found = false; for (i = 0; devs[i]; i++) { if (use_serial_number) { uint32_t tmp; ret = jaylink_device_get_serial_number(devs[i], &tmp); if (ret == JAYLINK_ERR_NOT_AVAILABLE) { continue; } else if (ret != JAYLINK_OK) { msg_pwarn("jaylink_device_get_serial_number() failed: %s.\n", jaylink_strerror(ret)); continue; } if (serial_number != tmp) continue; } ret = jaylink_open(devs[i], &jaylink_devh); if (ret == JAYLINK_OK) { dev = devs[i]; device_found = true; break; } jaylink_devh = NULL; } jaylink_free_devices(devs, true); if (!device_found) { msg_perr("No J-Link device found.\n"); return 1; } size_t length; char *firmware_version; ret = jaylink_get_firmware_version(jaylink_devh, &firmware_version, &length); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_firmware_version() failed: %s.\n", jaylink_strerror(ret)); return 1; } else if (length > 0) { msg_pdbg("Firmware: %s\n", firmware_version); free(firmware_version); } ret = jaylink_device_get_serial_number(dev, &serial_number); if (ret == JAYLINK_OK) { msg_pdbg("S/N: %" PRIu32 "\n", serial_number); } else if (ret == JAYLINK_ERR_NOT_AVAILABLE) { msg_pdbg("S/N: N/A\n"); } else { msg_perr("jaylink_device_get_serial_number() failed: %s.\n", jaylink_strerror(ret)); return 1; } uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; memset(caps, 0, sizeof(caps)); ret = jaylink_get_caps(jaylink_devh, caps); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_caps() failed: %s.\n", jaylink_strerror(ret)); return 1; } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) { ret = jaylink_get_extended_caps(jaylink_devh, caps); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret)); return 1; } } uint32_t ifaces; ret = jaylink_get_available_interfaces(jaylink_devh, &ifaces); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret)); return 1; } if (!(ifaces & (1 << JAYLINK_TIF_JTAG))) { msg_perr("Device does not support JTAG interface.\n"); return 1; } ret = jaylink_select_interface(jaylink_devh, JAYLINK_TIF_JTAG, NULL); if (ret != JAYLINK_OK) { msg_perr("jaylink_select_interface() failed: %s.\n", jaylink_strerror(ret)); return 1; } struct jaylink_hardware_status hwstat; ret = jaylink_get_hardware_status(jaylink_devh, &hwstat); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_hardware_status() failed: %s.\n", jaylink_strerror(ret)); return 1; } msg_pdbg("VTarget: %u.%03u V\n", hwstat.target_voltage / 1000, hwstat.target_voltage % 1000); if (hwstat.target_voltage < MIN_TARGET_VOLTAGE) { msg_perr("Target voltage is below %u.%03u V. You need to attach VTref to the I/O voltage of " "the chip.\n", MIN_TARGET_VOLTAGE / 1000, MIN_TARGET_VOLTAGE % 1000); return 1; } struct jaylink_speed device_speeds; device_speeds.freq = DEFAULT_FREQ; device_speeds.div = DEFAULT_FREQ_DIV; if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) { ret = jaylink_get_speeds(jaylink_devh, &device_speeds); if (ret != JAYLINK_OK) { msg_perr("jaylink_get_speeds() failed: %s.\n", jaylink_strerror(ret)); return 1; } } device_speeds.freq /= 1000; msg_pdbg("Maximum SPI speed: %" PRIu32 " kHz\n", device_speeds.freq / device_speeds.div); if (!speed) { speed = device_speeds.freq / device_speeds.div; msg_pdbg("SPI speed not specified, using %lu kHz.\n", speed); } if (speed > (device_speeds.freq / device_speeds.div)) { msg_perr("Specified SPI speed of %lu kHz is too high. Maximum is %" PRIu32 " kHz.\n", speed, device_speeds.freq / device_speeds.div); return 1; } ret = jaylink_set_speed(jaylink_devh, speed); if (ret != JAYLINK_OK) { msg_perr("jaylink_set_speed() failed: %s.\n", jaylink_strerror(ret)); return 1; } msg_pdbg("SPI speed: %lu kHz\n", speed); /* Ensure that the CS signal is not active initially. */ if (!deassert_cs()) return 1; register_spi_master(&spi_master_jlink_spi); return 0; }
static int jlink_init(void) { 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; ret = jaylink_init(&jayctx); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror_name(ret)); return ERROR_JTAG_INIT_FAILED; } ret = jaylink_get_device_list(jayctx, &devs); if (ret < 0) { LOG_ERROR("jaylink_get_device_list() failed: %s.", jaylink_strerror_name(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } found_device = false; if (!use_serial_number && !use_usb_address) LOG_INFO("No device selected, using first device."); for (i = 0; devs[i]; i++) { jaylink_device_get_serial_number(devs[i], &tmp); ret = jaylink_device_get_usb_address(devs[i]); if (use_usb_address && usb_address != ret) continue; if (use_serial_number && tmp != serial_number) continue; ret = jaylink_open(devs[i], &devh); if (ret != JAYLINK_OK) { LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret)); continue; } found_device = true; break; } jaylink_free_device_list(devs, 1); if (!found_device) { LOG_ERROR("No J-Link device found."); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } /* * Be careful with changing the following initialization sequence because * some devices are known to be sensitive regarding the order. */ ret = jaylink_get_firmware_version(devh, &firmware_version); if (ret > 0) { LOG_INFO("%s", firmware_version); free(firmware_version); } else if (!ret) { LOG_WARNING("Device responds empty firmware version string."); } else { LOG_ERROR("jaylink_get_firmware_version() failed: %s.", jaylink_strerror_name(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } 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_name(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) { ret = jaylink_get_extended_caps(devh, caps); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_extended_caps() failed: %s.", jaylink_strerror_name(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } } jtag_command_version = JAYLINK_JTAG_V2; if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_HW_VERSION)) { ret = jaylink_get_hardware_version(devh, &hwver); if (ret != JAYLINK_OK) { LOG_ERROR("Failed to retrieve hardware version: %s.", jaylink_strerror_name(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("Hardware version: %u.%02u", hwver.major, hwver.minor); if (hwver.major >= 5) jtag_command_version = JAYLINK_JTAG_V3; } if (iface == JAYLINK_TIF_SWD) { /* * Adjust the SWD transaction buffer size in case there is already * allocated memory on the device. This happens for example if the * memory for SWO capturing is still allocated because the software * which used the device before has not been shut down properly. */ if (!adjust_swd_buffer_size()) { jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { if (!read_device_config(&config)) { LOG_ERROR("Failed to read device configuration data."); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } memcpy(&tmp_config, &config, sizeof(struct device_config)); } ret = jaylink_get_hardware_status(devh, &hwstatus); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_hardware_status() failed: %s.", jaylink_strerror_name(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("VTarget = %u.%03u V", hwstatus.target_voltage / 1000, hwstatus.target_voltage % 1000); conn.handle = 0; conn.pid = 0; conn.hid = 0; conn.iid = 0; conn.cid = 0; ret = jlink_register(); if (ret != ERROR_OK) { jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } ret = select_interface(); if (ret != ERROR_OK) { jaylink_close(devh); jaylink_exit(jayctx); return ret; } jlink_reset(0, 0); jtag_sleep(3000); jlink_tap_init(); jlink_speed(jtag_get_speed_khz()); if (iface == JAYLINK_TIF_JTAG) { /* * J-Link devices with firmware version v5 and v6 seems to have an issue * if the first tap move is not divisible by 8, so we send a TLR on * first power up. */ uint8_t tms = 0xff; jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 8); jlink_flush(); } return ERROR_OK; }