X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjtag%2Fdrivers%2Fulink.c;h=5c58da355c2f6f23fbc0eee10e5c749259d4d827;hb=16b6b5e7a86353dbc0c4823fe3d772c0faca7c1c;hp=049989bf257a4ba219029620a73a6b027eea1857;hpb=b6e4d26695bd2268638ad52a1860f1c849b177cf;p=openocd diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 049989bf..5c58da35 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -22,6 +22,7 @@ #include "config.h" #endif +#include #include #include #include @@ -94,6 +95,15 @@ enum ulink_payload_direction 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). * @@ -138,17 +148,21 @@ struct ulink_cmd { 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 *****************************/ @@ -169,19 +183,19 @@ int ulink_write_firmware_section(struct ulink *device, 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 @@ -196,11 +210,15 @@ int ulink_append_get_signals_cmd(struct ulink *device); 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); @@ -211,8 +229,9 @@ int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); 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) */ @@ -502,7 +521,7 @@ void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) * @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; @@ -559,7 +578,7 @@ int ulink_allocate_payload(ulink_cmd_t *ulink_cmd, int size, 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) { @@ -587,8 +606,8 @@ int ulink_get_queue_size(struct ulink *device, */ 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 */ @@ -627,7 +646,7 @@ void ulink_clear_queue(struct ulink *device) * @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; @@ -682,7 +701,7 @@ int ulink_append_queue(struct ulink *device, ulink_cmd_t *ulink_cmd) */ 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]; @@ -780,6 +799,9 @@ const char * ulink_cmd_id_string(uint8_t id) 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; @@ -812,17 +834,18 @@ const char * ulink_cmd_id_string(uint8_t id) * * @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); } /** @@ -832,7 +855,7 @@ void ulink_print_command(ulink_cmd_t *ulink_cmd) */ void ulink_print_queue(struct ulink *device) { - ulink_cmd_t *current; + struct ulink_cmd *current; printf("OpenULINK command queue:\n"); @@ -878,7 +901,7 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, 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; @@ -902,18 +925,32 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, } /* 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: @@ -970,14 +1007,19 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, 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); @@ -1003,14 +1045,19 @@ int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, */ 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); @@ -1033,7 +1080,7 @@ int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) */ 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) { @@ -1073,7 +1120,7 @@ int ulink_append_get_signals_cmd(struct ulink *device) 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) { @@ -1105,7 +1152,7 @@ int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, */ 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) { @@ -1131,16 +1178,18 @@ int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) * 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) { @@ -1149,16 +1198,47 @@ int ulink_append_configure_tck_cmd(struct ulink *device, uint8_t delay_scan, 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); } @@ -1180,7 +1260,7 @@ int ulink_append_configure_tck_cmd(struct ulink *device, uint8_t delay_scan, */ 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) { @@ -1210,7 +1290,7 @@ int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) */ 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) { @@ -1230,6 +1310,165 @@ int ulink_append_test_cmd(struct ulink *device) 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 ******************/ /** @@ -1532,7 +1771,57 @@ int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) */ 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; } @@ -1551,6 +1840,55 @@ int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) 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 * @@ -1558,7 +1896,7 @@ int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) * @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; @@ -1591,7 +1929,7 @@ int ulink_post_process_scan(ulink_cmd_t *ulink_cmd) */ int ulink_post_process_queue(struct ulink *device) { - ulink_cmd_t *current; + struct ulink_cmd *current; struct jtag_command *openocd_cmd; int ret; @@ -1612,6 +1950,7 @@ int ulink_post_process_queue(struct ulink *device) case JTAG_RESET: case JTAG_PATHMOVE: case JTAG_SLEEP: + case JTAG_STABLECLOCKS: /* Nothing to do for these commands */ ret = ERROR_OK; break; @@ -1672,6 +2011,9 @@ static int ulink_execute_queue(void) 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"); @@ -1705,26 +2047,108 @@ static int ulink_execute_queue(void) /** * 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; } @@ -1732,30 +2156,38 @@ static int ulink_khz(int khz, int *jtag_speed) /** * 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; } @@ -1888,10 +2320,9 @@ COMMAND_HANDLER(ulink_download_firmware_handler) { 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]);