#include "config.h"
#endif
+#include <math.h>
#include <jtag/interface.h>
#include <jtag/commands.h>
#include <target/image.h>
PAYLOAD_DIRECTION_IN
};
+enum ulink_delay_type
+{
+ DELAY_CLOCK_TCK,
+ DELAY_CLOCK_TMS,
+ DELAY_SCAN_IN,
+ DELAY_SCAN_OUT,
+ DELAY_SCAN_IO
+};
+
/**
* OpenULINK command (OpenULINK command queue element).
*
struct ulink_cmd *next; ///< Pointer to next command (linked list)
};
-typedef struct ulink_cmd ulink_cmd_t;
-
/** Describes one driver instance */
struct ulink
{
struct usb_dev_handle *usb_handle;
enum ulink_type type;
- int commands_in_queue; ///< Number of commands in queue
- ulink_cmd_t *queue_start; ///< Pointer to first command in queue
- ulink_cmd_t *queue_end; ///< Pointer to last command in queue
+ int delay_scan_in; ///< Delay value for SCAN_IN commands
+ int delay_scan_out; ///< Delay value for SCAN_OUT commands
+ int delay_scan_io; ///< Delay value for SCAN_IO commands
+ int delay_clock_tck; ///< Delay value for CLOCK_TMS commands
+ int delay_clock_tms; ///< Delay value for CLOCK_TCK commands
+
+ int commands_in_queue; ///< Number of commands in queue
+ struct ulink_cmd *queue_start; ///< Pointer to first command in queue
+ struct ulink_cmd *queue_end; ///< Pointer to last command in queue
};
/**************************** Function Prototypes *****************************/
void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals);
/* OpenULINK command generation helper functions */
-int ulink_allocate_payload(ulink_cmd_t *ulink_cmd, int size,
+int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
enum ulink_payload_direction direction);
/* OpenULINK command queue helper functions */
int ulink_get_queue_size(struct ulink *device,
enum ulink_payload_direction direction);
void ulink_clear_queue(struct ulink *device);
-int ulink_append_queue(struct ulink *device, ulink_cmd_t *ulink_cmd);
+int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd);
int ulink_execute_queued_commands(struct ulink *device, int timeout);
#ifdef _DEBUG_JTAG_IO_
const char * ulink_cmd_id_string(uint8_t id);
-void ulink_print_command(ulink_cmd_t *ulink_cmd);
+void ulink_print_command(struct ulink_cmd *ulink_cmd);
void ulink_print_queue(struct ulink *device);
#endif
int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
uint8_t high);
int ulink_append_sleep_cmd(struct ulink *device, uint32_t us);
-int ulink_append_configure_tck_cmd(struct ulink *device, uint8_t delay_scan,
- uint8_t delay_tck, uint8_t delay_tms);
+int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in,
+ int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms);
int ulink_append_led_cmd(struct ulink *device, uint8_t led_state);
int ulink_append_test_cmd(struct ulink *device);
+/* OpenULINK TCK frequency helper functions */
+int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay);
+int ulink_calculate_frequency(enum ulink_delay_type type, int delay, long *f);
+
/* Interface between OpenULINK and OpenOCD */
static void ulink_set_end_state(tap_state_t endstate);
int ulink_queue_statemove(struct ulink *device);
int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd);
int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd);
+int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd);
-int ulink_post_process_scan(ulink_cmd_t *ulink_cmd);
+int ulink_post_process_scan(struct ulink_cmd *ulink_cmd);
int ulink_post_process_queue(struct ulink *device);
/* JTAG driver functions (registered in struct jtag_interface) */
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
-int ulink_allocate_payload(ulink_cmd_t *ulink_cmd, int size,
+int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size,
enum ulink_payload_direction direction)
{
uint8_t *payload;
int ulink_get_queue_size(struct ulink *device,
enum ulink_payload_direction direction)
{
- ulink_cmd_t *current = device->queue_start;
+ struct ulink_cmd *current = device->queue_start;
int sum = 0;
while (current != NULL) {
*/
void ulink_clear_queue(struct ulink *device)
{
- ulink_cmd_t *current = device->queue_start;
- ulink_cmd_t *next = NULL;
+ struct ulink_cmd *current = device->queue_start;
+ struct ulink_cmd *next = NULL;
while (current != NULL) {
/* Save pointer to next element */
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
-int ulink_append_queue(struct ulink *device, ulink_cmd_t *ulink_cmd)
+int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
{
int newsize_out, newsize_in;
int ret;
*/
int ulink_execute_queued_commands(struct ulink *device, int timeout)
{
- ulink_cmd_t *current;
+ struct ulink_cmd *current;
int ret, i, index_out, index_in, count_out, count_in;
uint8_t buffer[64];
case CMD_CLOCK_TCK:
return "CMD_CLOCK_TCK";
break;
+ case CMD_SLOW_CLOCK_TCK:
+ return "CMD_SLOW_CLOCK_TCK";
+ break;
case CMD_SLEEP_US:
return "CMD_SLEEP_US";
break;
*
* @param ulink_cmd pointer to OpenULINK command.
*/
-void ulink_print_command(ulink_cmd_t *ulink_cmd)
+void ulink_print_command(struct ulink_cmd *ulink_cmd)
{
int i;
- printf(" %-22s | OUT size = %i, bytes = 0x", ulink_cmd_id_string(ulink_cmd->id),
- ulink_cmd->payload_out_size);
+ printf(" %-22s | OUT size = %i, bytes = 0x",
+ ulink_cmd_id_string(ulink_cmd->id), ulink_cmd->payload_out_size);
for (i = 0; i < ulink_cmd->payload_out_size; i++) {
printf("%02X ", ulink_cmd->payload_out[i]);
}
- printf("\n | IN size = %i\n", ulink_cmd->payload_in_size);
+ printf("\n | IN size = %i\n",
+ ulink_cmd->payload_in_size);
}
/**
*/
void ulink_print_queue(struct ulink *device)
{
- ulink_cmd_t *current;
+ struct ulink_cmd *current;
printf("OpenULINK command queue:\n");
uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end,
uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret, i, scan_size_bytes;
uint8_t bits_last_byte;
}
/* Allocate out_payload depending on scan type */
- // TODO: set command ID depending on interface speed settings (slow scan)
switch (scan_type) {
case SCAN_IN:
- cmd->id = CMD_SCAN_IN;
+ if (device->delay_scan_in < 0) {
+ cmd->id = CMD_SCAN_IN;
+ }
+ else {
+ cmd->id = CMD_SLOW_SCAN_IN;
+ }
ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT);
break;
case SCAN_OUT:
- cmd->id = CMD_SCAN_OUT;
+ if (device->delay_scan_out < 0) {
+ cmd->id = CMD_SCAN_OUT;
+ }
+ else {
+ cmd->id = CMD_SLOW_SCAN_OUT;
+ }
ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT);
break;
case SCAN_IO:
- cmd->id = CMD_SCAN_IO;
+ if (device->delay_scan_io < 0) {
+ cmd->id = CMD_SCAN_IO;
+ }
+ else {
+ cmd->id = CMD_SLOW_SCAN_IO;
+ }
ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT);
break;
default:
int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count,
uint8_t sequence)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
return ERROR_FAIL;
}
- cmd->id = CMD_CLOCK_TMS;
+ if (device->delay_clock_tms < 0) {
+ cmd->id = CMD_CLOCK_TMS;
+ }
+ else {
+ cmd->id = CMD_SLOW_CLOCK_TMS;
+ }
/* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */
ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT);
*/
int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
return ERROR_FAIL;
}
- cmd->id = CMD_CLOCK_TCK;
+ if (device->delay_clock_tck < 0) {
+ cmd->id = CMD_CLOCK_TCK;
+ }
+ else {
+ cmd->id = CMD_SLOW_CLOCK_TCK;
+ }
/* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */
ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT);
*/
int ulink_append_get_signals_cmd(struct ulink *device)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low,
uint8_t high)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
*/
int ulink_append_sleep_cmd(struct ulink *device, uint32_t us)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
* Set TCK delay counters
*
* @param device pointer to struct ulink identifying ULINK driver instance.
- * @param delay_scan delay count top value in jtag_slow_scan() functions
- * @param delay_tck delay count top value in jtag_clock_tck() function
- * @param delay_tms delay count top value in jtag_slow_clock_tms() function
+ * @param delay_scan_in delay count top value in jtag_slow_scan_in() function.
+ * @param delay_scan_out delay count top value in jtag_slow_scan_out() function.
+ * @param delay_scan_io delay count top value in jtag_slow_scan_io() function.
+ * @param delay_tck delay count top value in jtag_clock_tck() function.
+ * @param delay_tms delay count top value in jtag_slow_clock_tms() function.
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
-int ulink_append_configure_tck_cmd(struct ulink *device, uint8_t delay_scan,
- uint8_t delay_tck, uint8_t delay_tms)
+int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in,
+ int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
cmd->id = CMD_CONFIGURE_TCK_FREQ;
- /* CMD_CONFIGURE_TCK_FREQ has three OUT payload bytes and zero
+ /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero
* IN payload bytes */
- ret = ulink_allocate_payload(cmd, 3, PAYLOAD_DIRECTION_OUT);
+ ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT);
if (ret != ERROR_OK) {
return ret;
}
- cmd->payload_out[0] = delay_scan;
- cmd->payload_out[1] = delay_tck;
- cmd->payload_out[2] = delay_tms;
+ if (delay_scan_in < 0) {
+ cmd->payload_out[0] = 0;
+ }
+ else {
+ cmd->payload_out[0] = (uint8_t)delay_scan_in;
+ }
+
+ if (delay_scan_out < 0) {
+ cmd->payload_out[1] = 0;
+ }
+ else {
+ cmd->payload_out[1] = (uint8_t)delay_scan_out;
+ }
+
+ if (delay_scan_io < 0) {
+ cmd->payload_out[2] = 0;
+ }
+ else {
+ cmd->payload_out[2] = (uint8_t)delay_scan_io;
+ }
+
+ if (delay_tck < 0) {
+ cmd->payload_out[3] = 0;
+ }
+ else {
+ cmd->payload_out[3] = (uint8_t)delay_tck;
+ }
+
+ if (delay_tms < 0) {
+ cmd->payload_out[4] = 0;
+ }
+ else {
+ cmd->payload_out[4] = (uint8_t)delay_tms;
+ }
return ulink_append_queue(device, cmd);
}
*/
int ulink_append_led_cmd(struct ulink *device, uint8_t led_state)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
*/
int ulink_append_test_cmd(struct ulink *device)
{
- ulink_cmd_t *cmd = calloc(1, sizeof(ulink_cmd_t));
+ struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd));
int ret;
if (cmd == NULL) {
return ulink_append_queue(device, cmd);
}
+/****************** OpenULINK TCK frequency helper functions ******************/
+
+/**
+ * Calculate delay values for a given TCK frequency.
+ *
+ * The OpenULINK firmware uses five different speed values for different
+ * commands. These speed values are calculated in these functions.
+ *
+ * The five different commands which support variable TCK frequency are
+ * implemented twice in the firmware:
+ * 1. Maximum possible frequency without any artificial delay
+ * 2. Variable frequency with artificial linear delay loop
+ *
+ * To set the ULINK to maximum frequency, it is only neccessary to use the
+ * corresponding command IDs. To set the ULINK to a lower frequency, the
+ * delay loop top values have to be calculated first. Then, a
+ * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ULINK device.
+ *
+ * The delay values are described by linear equations:
+ * t = k * x + d
+ * (t = period, k = constant, x = delay value, d = constant)
+ *
+ * Thus, the delay can be calculated as in the following equation:
+ * x = (t - d) / k
+ *
+ * The constants in these equations have been determined and validated by
+ * measuring the frequency resulting from different delay values.
+ *
+ * @param type for which command to calculate the delay value.
+ * @param f TCK frequency for which to calculate the delay value in Hz.
+ * @param delay where to store resulting delay value.
+ * @return on success: ERROR_OK
+ * @return on failure: ERROR_FAIL
+ */
+int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay)
+{
+ float t, x, x_ceil;
+
+ /* Calculate period of requested TCK frequency */
+ t = 1.0 / (float)(f);
+
+ switch (type) {
+ case DELAY_CLOCK_TCK:
+ x = (t - (float)(6E-6)) / (float)(4E-6);
+ break;
+ case DELAY_CLOCK_TMS:
+ x = (t - (float)(8.5E-6)) / (float)(4E-6);
+ break;
+ case DELAY_SCAN_IN:
+ x = (t - (float)(8.8308E-6)) / (float)(4E-6);
+ break;
+ case DELAY_SCAN_OUT:
+ x = (t - (float)(1.0527E-5)) / (float)(4E-6);
+ break;
+ case DELAY_SCAN_IO:
+ x = (t - (float)(1.3132E-5)) / (float)(4E-6);
+ break;
+ default:
+ return ERROR_FAIL;
+ break;
+ }
+
+ /* Check if the delay value is negative. This happens when a frequency is
+ * requested that is too high for the delay loop implementation. In this
+ * case, set delay value to zero. */
+ if (x < 0) {
+ x = 0;
+ }
+
+ /* We need to convert the exact delay value to an integer. Therefore, we
+ * round the exact value UP to ensure that the resulting frequency is NOT
+ * higher than the requested frequency. */
+ x_ceil = ceilf(x);
+
+ /* Check if the value is within limits */
+ if (x_ceil > 255) {
+ return ERROR_FAIL;
+ }
+
+ *delay = (int)x_ceil;
+
+ return ERROR_OK;
+}
+
+/**
+ * Calculate frequency for a given delay value.
+ *
+ * Similar to the #ulink_calculate_delay function, this function calculates the
+ * TCK frequency for a given delay value by using linear equations of the form:
+ * t = k * x + d
+ * (t = period, k = constant, x = delay value, d = constant)
+ *
+ * @param type for which command to calculate the delay value.
+ * @param delay delay value for which to calculate the resulting TCK frequency.
+ * @param f where to store the resulting TCK frequency.
+ * @return on success: ERROR_OK
+ * @return on failure: ERROR_FAIL
+ */
+int ulink_calculate_frequency(enum ulink_delay_type type, int delay, long *f)
+{
+ float t, f_float, f_rounded;
+
+ if (delay > 255) {
+ return ERROR_FAIL;
+ }
+
+ switch (type) {
+ case DELAY_CLOCK_TCK:
+ if (delay < 0) {
+ t = (float)(2.666E-6);
+ }
+ else {
+ t = (float)(4E-6) * (float)(delay) + (float)(6E-6);
+ }
+ break;
+ case DELAY_CLOCK_TMS:
+ if (delay < 0) {
+ t = (float)(5.666E-6);
+ }
+ else {
+ t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6);
+ }
+ break;
+ case DELAY_SCAN_IN:
+ if (delay < 0) {
+ t = (float)(5.5E-6);
+ }
+ else {
+ t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6);
+ }
+ break;
+ case DELAY_SCAN_OUT:
+ if (delay < 0) {
+ t = (float)(7.0E-6);
+ }
+ else {
+ t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5);
+ }
+ break;
+ case DELAY_SCAN_IO:
+ if (delay < 0) {
+ t = (float)(9.926E-6);
+ }
+ else {
+ t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5);
+ }
+ break;
+ default:
+ return ERROR_FAIL;
+ break;
+ }
+
+ f_float = 1.0 / t;
+ f_rounded = roundf(f_float);
+ *f = (long)f_rounded;
+
+ return ERROR_OK;
+}
+
/******************* Interface between OpenULINK and OpenOCD ******************/
/**
*/
int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd)
{
- // TODO: Implement this!
+ int ret, i, num_states, batch_size, state_count;
+ tap_state_t *path;
+ uint8_t tms_sequence;
+
+ num_states = cmd->cmd.pathmove->num_states;
+ path = cmd->cmd.pathmove->path;
+ state_count = 0;
+
+ while (num_states > 0) {
+ tms_sequence = 0;
+
+ /* Determine batch size */
+ if (num_states >= 8) {
+ batch_size = 8;
+ }
+ else {
+ batch_size = num_states;
+ }
+
+ for (i = 0; i < batch_size; i++) {
+ if (tap_state_transition(tap_get_state(), false) == path[state_count]) {
+ /* Append '0' transition: clear bit 'i' in tms_sequence */
+ buf_set_u32(&tms_sequence, i, 1, 0x0);
+ }
+ else if (tap_state_transition(tap_get_state(), true)
+ == path[state_count]) {
+ /* Append '1' transition: set bit 'i' in tms_sequence */
+ buf_set_u32(&tms_sequence, i, 1, 0x1);
+ }
+ else {
+ /* Invalid state transition */
+ LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition",
+ tap_state_name(tap_get_state()),
+ tap_state_name(path[state_count]));
+ return ERROR_FAIL;
+ }
+
+ tap_set_state(path[state_count]);
+ state_count++;
+ num_states--;
+ }
+
+ /* Append CLOCK_TMS command to OpenULINK command queue */
+ LOG_INFO(
+ "pathmove batch: count = %i, sequence = 0x%x", batch_size, tms_sequence);
+ ret = ulink_append_clock_tms_cmd(ulink_handle, batch_size, tms_sequence);
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+ }
+
return ERROR_OK;
}
return ulink_append_sleep_cmd(device, cmd->cmd.sleep->us);
}
+/**
+ * Generate TCK cycles while remaining in a stable state.
+ *
+ * @param device pointer to struct ulink identifying ULINK driver instance.
+ * @param cmd pointer to the command that shall be executed.
+ */
+int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd)
+{
+ int ret;
+ unsigned num_cycles;
+
+ if (!tap_is_state_stable(tap_get_state())) {
+ LOG_ERROR("JTAG_STABLECLOCKS: state not stable");
+ return ERROR_FAIL;
+ }
+
+ num_cycles = cmd->cmd.stableclocks->num_cycles;
+
+ /* TMS stays either high (Test Logic Reset state) or low (all other states) */
+ if (tap_get_state() == TAP_RESET) {
+ ret = ulink_append_set_signals_cmd(device, 0, SIGNAL_TMS);
+ }
+ else {
+ ret = ulink_append_set_signals_cmd(device, SIGNAL_TMS, 0);
+ }
+
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+
+ while (num_cycles > 0) {
+ if (num_cycles > 0xFFFF) {
+ /* OpenULINK CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */
+ ret = ulink_append_clock_tck_cmd(device, 0xFFFF);
+ num_cycles -= 0xFFFF;
+ }
+ else {
+ ret = ulink_append_clock_tck_cmd(device, num_cycles);
+ num_cycles = 0;
+ }
+
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+ }
+
+ return ERROR_OK;
+}
+
/**
* Post-process JTAG_SCAN command
*
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
-int ulink_post_process_scan(ulink_cmd_t *ulink_cmd)
+int ulink_post_process_scan(struct ulink_cmd *ulink_cmd)
{
struct jtag_command *cmd = ulink_cmd->cmd_origin;
int ret;
*/
int ulink_post_process_queue(struct ulink *device)
{
- ulink_cmd_t *current;
+ struct ulink_cmd *current;
struct jtag_command *openocd_cmd;
int ret;
case JTAG_RESET:
case JTAG_PATHMOVE:
case JTAG_SLEEP:
+ case JTAG_STABLECLOCKS:
/* Nothing to do for these commands */
ret = ERROR_OK;
break;
case JTAG_SLEEP:
ret = ulink_queue_sleep(ulink_handle, cmd);
break;
+ case JTAG_STABLECLOCKS:
+ ret = ulink_queue_stableclocks(ulink_handle, cmd);
+ break;
default:
ret = ERROR_FAIL;
LOG_ERROR("BUG: encountered unknown JTAG command type");
/**
* Set the TCK frequency of the ULINK adapter.
*
- * @param khz ???
- * @param jtag_speed ???
+ * @param khz desired JTAG TCK frequency.
+ * @param jtag_speed where to store corresponding adapter-specific speed value.
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
static int ulink_khz(int khz, int *jtag_speed)
{
+ int ret;
+
if (khz == 0) {
LOG_ERROR("RCLK not supported");
return ERROR_FAIL;
}
- LOG_INFO("ulink_khz: %i kHz", khz);
+ /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency
+ * setting can be done independently from all other commands. */
+ if (khz >= 375) {
+ ulink_handle->delay_clock_tck = -1;
+ }
+ else {
+ ret = ulink_calculate_delay(DELAY_CLOCK_TCK, khz * 1000,
+ &ulink_handle->delay_clock_tck);
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+ }
- /* ULINK maximum TCK frequency is ~ 150 kHz */
- if (khz > 150) {
- return ERROR_FAIL;
+ /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the
+ * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS
+ * commands, all SCAN commands MUST also use the variable frequency
+ * implementation! */
+ if (khz >= 176) {
+ ulink_handle->delay_clock_tms = -1;
+ ulink_handle->delay_scan_in = -1;
+ ulink_handle->delay_scan_out = -1;
+ ulink_handle->delay_scan_io = -1;
}
+ else {
+ ret = ulink_calculate_delay(DELAY_CLOCK_TMS, khz * 1000,
+ &ulink_handle->delay_clock_tms);
+ if (ret != ERROR_OK) {
+ return ret;
+ }
- *jtag_speed = 0;
+ ret = ulink_calculate_delay(DELAY_SCAN_IN, khz * 1000,
+ &ulink_handle->delay_scan_in);
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+
+ ret = ulink_calculate_delay(DELAY_SCAN_OUT, khz * 1000,
+ &ulink_handle->delay_scan_out);
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+
+ ret = ulink_calculate_delay(DELAY_SCAN_IO, khz * 1000,
+ &ulink_handle->delay_scan_io);
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+ }
+
+#ifdef _DEBUG_JTAG_IO_
+ long f_tck, f_tms, f_scan_in, f_scan_out, f_scan_io;
+
+ ulink_calculate_frequency(DELAY_CLOCK_TCK, ulink_handle->delay_clock_tck,
+ &f_tck);
+ ulink_calculate_frequency(DELAY_CLOCK_TMS, ulink_handle->delay_clock_tms,
+ &f_tms);
+ ulink_calculate_frequency(DELAY_SCAN_IN, ulink_handle->delay_scan_in,
+ &f_scan_in);
+ ulink_calculate_frequency(DELAY_SCAN_OUT, ulink_handle->delay_scan_out,
+ &f_scan_out);
+ ulink_calculate_frequency(DELAY_SCAN_IO, ulink_handle->delay_scan_io,
+ &f_scan_io);
+
+ DEBUG_JTAG_IO("ULINK TCK setup: delay_tck = %i (%li Hz),",
+ ulink_handle->delay_clock_tck, f_tck);
+ DEBUG_JTAG_IO(" delay_tms = %i (%li Hz),",
+ ulink_handle->delay_clock_tms, f_tms);
+ DEBUG_JTAG_IO(" delay_scan_in = %i (%li Hz),",
+ ulink_handle->delay_scan_in, f_scan_in);
+ DEBUG_JTAG_IO(" delay_scan_out = %i (%li Hz),",
+ ulink_handle->delay_scan_out, f_scan_out);
+ DEBUG_JTAG_IO(" delay_scan_io = %i (%li Hz),",
+ ulink_handle->delay_scan_io, f_scan_io);
+#endif
+
+ /* Configure the ULINK device with the new delay values */
+ ret = ulink_append_configure_tck_cmd(ulink_handle,
+ ulink_handle->delay_scan_in,
+ ulink_handle->delay_scan_out,
+ ulink_handle->delay_scan_io,
+ ulink_handle->delay_clock_tck,
+ ulink_handle->delay_clock_tms);
+
+ if (ret != ERROR_OK) {
+ return ret;
+ }
+
+ *jtag_speed = khz;
return ERROR_OK;
}
/**
* Set the TCK frequency of the ULINK adapter.
*
- * @param speed ???
+ * Because of the way the TCK frequency is set up in the OpenULINK firmware,
+ * there are five different speed settings. To simplify things, the
+ * adapter-specific speed setting value is identical to the TCK frequency in
+ * khz.
+ *
+ * @param speed desired adapter-specific speed value.
* @return on success: ERROR_OK
* @return on failure: ERROR_FAIL
*/
static int ulink_speed(int speed)
{
- return ERROR_OK;
+ int dummy;
+
+ return ulink_khz(speed, &dummy);
}
/**
+ * Convert adapter-specific speed value to corresponding TCK frequency in kHz.
+ *
+ * Because of the way the TCK frequency is set up in the OpenULINK firmware,
+ * there are five different speed settings. To simplify things, the
+ * adapter-specific speed setting value is identical to the TCK frequency in
+ * khz.
*
+ * @param speed adapter-specific speed value.
+ * @param khz where to store corresponding TCK frequency in kHz.
+ * @return on success: ERROR_OK
+ * @return on failure: ERROR_FAIL
*/
static int ulink_speed_div(int speed, int *khz)
{
- LOG_INFO("ulink_speed_div: %i", speed);
-
- switch (speed) {
- case 0:
- *khz = 150;
- break;
- case 1:
- *khz = 100;
- break;
- }
+ *khz = speed;
return ERROR_OK;
}
{
int ret;
- if (CMD_ARGC != 1) {
- LOG_ERROR("Need exactly one argument to ulink_download_firmware");
- return ERROR_FAIL;
- }
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
LOG_INFO("Downloading ULINK firmware image %s", CMD_ARGV[0]);