X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fcore.c;h=8cb4da558edaef6a876ae78d0a7e7351b9803a8b;hp=4e6e5b59fec612ea6ae44dc218e80395765d30f4;hb=9a9ebfb924553e0f4837c4ef77b900f1f5d824f1;hpb=8b994145b849c40b0a195c3fb332b9770b2f9097 diff --git a/src/jtag/core.c b/src/jtag/core.c index 4e6e5b59fe..8cb4da558e 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -60,11 +60,15 @@ static int jtag_error = ERROR_OK; static const char *jtag_event_strings[] = { - [JTAG_TRST_ASSERTED] = "JTAG controller reset (RESET or TRST)", + [JTAG_TRST_ASSERTED] = "JTAG controller reset (TLR or TRST)", [JTAG_TAP_EVENT_ENABLE] = "TAP enabled", [JTAG_TAP_EVENT_DISABLE] = "TAP disabled", }; +/* + * JTAG adapters must initialize with TRST and SRST de-asserted + * (they're negative logic, so that means *high*) + */ static int jtag_trst = 0; static int jtag_srst = 0; @@ -101,8 +105,9 @@ static jtag_event_callback_t *jtag_event_callbacks; /* speed in kHz*/ static int speed_khz = 0; -/* flag if the kHz speed was defined */ -static bool hasKHz = false; +/* speed to fallback to when RCLK is requested but not supported */ +static int rclk_fallback_speed_khz = 0; +static enum {CLOCK_MODE_SPEED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode; static int jtag_speed = 0; static struct jtag_interface_s *jtag = NULL; @@ -580,102 +585,105 @@ void jtag_add_clocks(int num_cycles) void jtag_add_reset(int req_tlr_or_trst, int req_srst) { int trst_with_tlr = 0; + int new_srst = 0; + int new_trst = 0; - /* FIX!!! there are *many* different cases here. A better - * approach is needed for legal combinations of transitions... + /* Without SRST, we must use target-specific JTAG operations + * on each target; callers should not be requesting SRST when + * that signal doesn't exist. + * + * RESET_SRST_PULLS_TRST is a board or chip level quirk, which + * can kick in even if the JTAG adapter can't drive TRST. */ - if ((jtag_reset_config & RESET_HAS_SRST)&& - (jtag_reset_config & RESET_HAS_TRST)&& - ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0)) - { - if (((req_tlr_or_trst&&!jtag_trst)|| - (!req_tlr_or_trst && jtag_trst))&& - ((req_srst&&!jtag_srst)|| - (!req_srst && jtag_srst))) - { - /* FIX!!! srst_pulls_trst allows 1,1 => 0,0 transition.... */ - //LOG_ERROR("BUG: transition of req_tlr_or_trst and req_srst in the same jtag_add_reset() call is undefined"); + if (req_srst) { + if (!(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("BUG: can't assert SRST"); + jtag_set_error(ERROR_FAIL); + return; + } + if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0 + && !req_tlr_or_trst) { + LOG_ERROR("BUG: can't assert only SRST"); + jtag_set_error(ERROR_FAIL); + return; } + new_srst = 1; } - /* Make sure that jtag_reset_config allows the requested reset */ - /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */ - if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (!req_tlr_or_trst)) - { - LOG_ERROR("BUG: requested reset would assert trst"); - jtag_set_error(ERROR_FAIL); - return; + /* JTAG reset (entry to TAP_RESET state) can always be achieved + * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE + * state first. TRST accelerates it, and bypasses those states. + * + * RESET_TRST_PULLS_SRST is a board or chip level quirk, which + * can kick in even if the JTAG adapter can't drive SRST. + */ + if (req_tlr_or_trst) { + if (!(jtag_reset_config & RESET_HAS_TRST)) + trst_with_tlr = 1; + else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0 + && !req_srst) + trst_with_tlr = 1; + else + new_trst = 1; } - /* if TRST pulls SRST, we reset with TAP T-L-R */ - if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_tlr_or_trst)) && (req_srst == 0)) - { - trst_with_tlr = 1; - } + /* Maybe change TRST and/or SRST signal state */ + if (jtag_srst != new_srst || jtag_trst != new_trst) { + int retval; - if (req_srst && !(jtag_reset_config & RESET_HAS_SRST)) - { - LOG_ERROR("BUG: requested SRST assertion, but the current configuration doesn't support this"); - jtag_set_error(ERROR_FAIL); - return; - } + retval = interface_jtag_add_reset(new_trst, new_srst); + if (retval != ERROR_OK) + jtag_set_error(retval); + else + retval = jtag_execute_queue(); - if (req_tlr_or_trst) - { - if (!trst_with_tlr && (jtag_reset_config & RESET_HAS_TRST)) - { - jtag_trst = 1; - } else - { - trst_with_tlr = 1; + if (retval != ERROR_OK) { + LOG_ERROR("TRST/SRST error %d", retval); + return; } - } else - { - jtag_trst = 0; - } - - jtag_srst = req_srst; - - int retval = interface_jtag_add_reset(jtag_trst, jtag_srst); - if (retval != ERROR_OK) - { - jtag_set_error(retval); - return; } - jtag_execute_queue(); - if (jtag_srst) - { - LOG_DEBUG("SRST line asserted"); - } - else - { - LOG_DEBUG("SRST line released"); - if (jtag_nsrst_delay) - jtag_add_sleep(jtag_nsrst_delay * 1000); + /* SRST resets everything hooked up to that signal */ + if (jtag_srst != new_srst) { + jtag_srst = new_srst; + if (jtag_srst) + LOG_DEBUG("SRST line asserted"); + else { + LOG_DEBUG("SRST line released"); + if (jtag_nsrst_delay) + jtag_add_sleep(jtag_nsrst_delay * 1000); + } } - if (trst_with_tlr) - { - LOG_DEBUG("JTAG reset with RESET instead of TRST"); + /* Maybe enter the JTAG TAP_RESET state ... + * - using only TMS, TCK, and the JTAG state machine + * - or else more directly, using TRST + * + * TAP_RESET should be invisible to non-debug parts of the system. + */ + if (trst_with_tlr) { + LOG_DEBUG("JTAG reset with TLR instead of TRST"); jtag_set_end_state(TAP_RESET); jtag_add_tlr(); - return; - } - if (jtag_trst) - { - /* we just asserted nTRST, so we're now in Test-Logic-Reset, - * and inform possible listeners about this - */ - LOG_DEBUG("TRST line asserted"); - tap_set_state(TAP_RESET); - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - } - else - { - if (jtag_ntrst_delay) - jtag_add_sleep(jtag_ntrst_delay * 1000); + } else if (jtag_trst != new_trst) { + jtag_trst = new_trst; + if (jtag_trst) { + /* we just asserted nTRST, so we're now in TAP_RESET; + * inform possible listeners about this + * + * REVISIT asserting TRST is less significant than + * being in TAP_RESET ... both entries (TRST, TLR) + * should trigger a callback. + */ + LOG_DEBUG("TRST line asserted"); + tap_set_state(TAP_RESET); + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + } else { + LOG_DEBUG("TRST line released"); + if (jtag_ntrst_delay) + jtag_add_sleep(jtag_ntrst_delay * 1000); + } } } @@ -810,6 +818,7 @@ static int jtag_reset_callback(enum jtag_event event, void *priv) { tap->enabled = !tap->disabled_after_reset; + /* current instruction is either BYPASS or IDCODE */ buf_set_ones(tap->cur_instr, tap->ir_length); tap->bypass = 1; } @@ -930,7 +939,7 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap) /* If none of the expected ids matched, log an error */ if (ii != tap->expected_ids_cnt) { - LOG_INFO("JTAG Tap/device matched"); + LOG_DEBUG("JTAG Tap/device matched"); return true; } jtag_examine_chain_display(LOG_LVL_ERROR, "got", @@ -969,11 +978,13 @@ int jtag_examine_chain(void) for (unsigned bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;) { uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32); + tap->hasidcode = true; if ((idcode & 1) == 0) { /* LSB must not be 0, this indicates a device in bypass */ LOG_WARNING("Tap/Device does not have IDCODE"); idcode = 0; + tap->hasidcode = false; bit_count += 1; } @@ -1065,7 +1076,8 @@ int jtag_validate_chain(void) } val = buf_get_u32(ir_test, chain_pos, 2); - if (val != 0x1) + /* Only fail this check if we have IDCODE for this device */ + if ((val != 0x1)&&(tap->hasidcode)) { char *cbuf = buf_to_str(ir_test, total_ir_length, 16); LOG_ERROR("Could not validate JTAG scan chain, IR mismatch, scan returned 0x%s. tap=%s pos=%d expected 0x1 got %0x", cbuf, jtag_tap_name(tap), chain_pos, val); @@ -1140,16 +1152,33 @@ int jtag_interface_init(struct command_context_s *cmd_ctx) LOG_ERROR("JTAG interface has to be specified, see \"interface\" command"); return ERROR_JTAG_INVALID_INTERFACE; } - if (hasKHz) - { - jtag_interface->khz(jtag_get_speed_khz(), &jtag_speed); - hasKHz = false; - } + jtag = jtag_interface; if (jtag_interface->init() != ERROR_OK) + { + jtag = NULL; return ERROR_JTAG_INIT_FAILED; + } + + int requested_khz = jtag_get_speed_khz(); + int actual_khz = requested_khz; + int retval = jtag_get_speed_readable(&actual_khz); + if (ERROR_OK != retval) + LOG_INFO("interface specific clock speed value %d", jtag_get_speed()); + else if (actual_khz) + { + if ((CLOCK_MODE_RCLK == clock_mode) + || ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz)) + { + LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz" + , actual_khz); + } + else + LOG_INFO("clock speed %d kHz", actual_khz); + } + else + LOG_INFO("RCLK (adaptive clock speed)"); - jtag = jtag_interface; return ERROR_OK; } @@ -1205,11 +1234,11 @@ int jtag_init_reset(struct command_context_s *cmd_ctx) if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK) return retval; - LOG_DEBUG("Trying to bring the JTAG controller to life by asserting TRST / RESET"); + LOG_DEBUG("Trying to bring the JTAG controller to life by asserting TRST / TLR"); /* Reset can happen after a power cycle. * - * Ideally we would only assert TRST or run RESET before the target reset. + * Ideally we would only assert TRST or run TLR before the target reset. * * However w/srst_pulls_trst, trst is asserted together with the target * reset whether we want it or not. @@ -1222,7 +1251,7 @@ int jtag_init_reset(struct command_context_s *cmd_ctx) * NB! order matters!!!! srst *can* disconnect JTAG circuitry * */ - jtag_add_reset(1, 0); /* RESET or TRST */ + jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */ if (jtag_reset_config & RESET_HAS_SRST) { jtag_add_reset(1, 1); @@ -1255,20 +1284,15 @@ int jtag_init(struct command_context_s *cmd_ctx) return jtag_init_reset(cmd_ctx); } -void jtag_set_speed_khz(unsigned khz) -{ - speed_khz = khz; -} unsigned jtag_get_speed_khz(void) { return speed_khz; } -int jtag_config_khz(unsigned khz) -{ - LOG_DEBUG("handle jtag khz"); - jtag_set_speed_khz(khz); - int cur_speed = 0; +static int jtag_khz_to_speed(unsigned khz, int* speed) +{ + LOG_DEBUG("convert khz to interface specific speed value"); + speed_khz = khz; if (jtag != NULL) { LOG_DEBUG("have interface set up"); @@ -1276,33 +1300,84 @@ int jtag_config_khz(unsigned khz) int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1); if (ERROR_OK != retval) { - jtag_set_speed_khz(0); return retval; } - cur_speed = speed_div1; + *speed = speed_div1; } - return jtag_set_speed(cur_speed); + return ERROR_OK; } -int jtag_get_speed(void) +static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int* speed) { - return jtag_speed; + int retval = jtag_khz_to_speed(0, speed); + if ((ERROR_OK != retval) && fallback_speed_khz) + { + LOG_DEBUG("trying fallback speed..."); + retval = jtag_khz_to_speed(fallback_speed_khz, speed); + } + return retval; } -int jtag_set_speed(int speed) +static int jtag_set_speed(int speed) { jtag_speed = speed; /* this command can be called during CONFIG, * in which case jtag isn't initialized */ - hasKHz = !jtag; return jtag ? jtag->speed(speed) : ERROR_OK; } -int jtag_get_speed_readable(int *speed) +int jtag_config_speed(int speed) +{ + LOG_DEBUG("handle jtag speed"); + clock_mode = CLOCK_MODE_SPEED; + return jtag_set_speed(speed); +} + +int jtag_config_khz(unsigned khz) +{ + LOG_DEBUG("handle jtag khz"); + clock_mode = CLOCK_MODE_KHZ; + int speed = 0; + int retval = jtag_khz_to_speed(khz, &speed); + return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); +} + +int jtag_config_rclk(unsigned fallback_speed_khz) { - return jtag ? jtag->speed_div(jtag_get_speed(), speed) : ERROR_OK; + LOG_DEBUG("handle jtag rclk"); + clock_mode = CLOCK_MODE_RCLK; + rclk_fallback_speed_khz = fallback_speed_khz; + int speed = 0; + int retval = jtag_rclk_to_speed(fallback_speed_khz, &speed); + return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); } +int jtag_get_speed(void) +{ + int speed; + switch(clock_mode) + { + case CLOCK_MODE_SPEED: + speed = jtag_speed; + break; + case CLOCK_MODE_KHZ: + jtag_khz_to_speed(jtag_get_speed_khz(), &speed); + break; + case CLOCK_MODE_RCLK: + jtag_rclk_to_speed(rclk_fallback_speed_khz, &speed); + break; + default: + LOG_ERROR("BUG: unknown jtag clock mode"); + speed = 0; + break; + } + return speed; +} + +int jtag_get_speed_readable(int *khz) +{ + return jtag ? jtag->speed_div(jtag_get_speed(), khz) : ERROR_OK; +} void jtag_set_verify(bool enable) {