aboutsummaryrefslogtreecommitdiff
path: root/src/jtag/drivers/jlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jtag/drivers/jlink.c')
-rw-r--r--src/jtag/drivers/jlink.c167
1 files changed, 116 insertions, 51 deletions
diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c
index 09b3a85..1baf345 100644
--- a/src/jtag/drivers/jlink.c
+++ b/src/jtag/drivers/jlink.c
@@ -39,6 +39,7 @@
#include <jtag/swd.h>
#include <jtag/commands.h>
#include <jtag/drivers/jtag_usb_common.h>
+#include <target/cortex_m.h>
#include <libjaylink/libjaylink.h>
@@ -62,6 +63,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 +94,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);
@@ -247,16 +252,6 @@ 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);
@@ -282,9 +277,6 @@ 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;
@@ -952,6 +944,13 @@ 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;
@@ -1267,55 +1266,74 @@ 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)
{
- double min;
+ unsigned int presc;
double deviation;
+
+ presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1;
+
+ if (presc > TPIU_ACPR_MAX_SWOSCALER)
+ return false;
+
+ deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq));
+
+ if (deviation > SWO_MAX_FREQ_DEV)
+ return false;
+
+ *prescaler = presc;
+
+ return true;
+}
+
+static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed,
+ unsigned int traceclkin_freq, uint32_t *trace_freq,
+ uint16_t *prescaler)
+{
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)
+ 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) {
@@ -1334,6 +1352,11 @@ 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) {
@@ -1349,13 +1372,45 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
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 %u Hz instead.",
+ max_freq);
+ *trace_freq = max_freq;
+ } else if (*trace_freq < min_freq) {
+ LOG_INFO("Given SWO frequency too low, using %u 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 (!check_trace_freq(speed, *trace_freq))
- return ERROR_FAIL;
+ 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.");
- LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size);
+ 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_INFO("Using SWO frequency of %u Hz.", *trace_freq);
+ }
ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq,
buffer_size);
@@ -1365,6 +1420,9 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
return ERROR_FAIL;
}
+ LOG_DEBUG("Using %u bytes device memory for trace capturing.",
+ buffer_size);
+
/*
* Adjust the SWD transaction buffer size as starting SWO capturing
* allocates device internal memory.
@@ -1470,7 +1528,7 @@ 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;
@@ -2212,17 +2270,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,
};