X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fcore.c;h=854236f3d15346d31b5d3bba24e89c4803ff34ea;hp=97179192e5681336701047587b4d3fc59a6e093f;hb=39b57471bfd92ef0d9a3aceb69f40c1335f5b62f;hpb=e961bd14d93a3c4bae5ff52e28e049b1a96dd485 diff --git a/src/jtag/core.c b/src/jtag/core.c index 97179192e5..854236f3d1 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1,16 +1,16 @@ /*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * + * Copyright (C) 2009 Zachary T Welch * + * zw@superlucidity.net * * * - * Copyright (C) 2007,2008 Øyvind Harboe * + * Copyright (C) 2007,2008,2009 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * - * Copyright (C) 2009 Zachary T Welch * - * zw@superlucidity.net * + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -60,9 +60,9 @@ static int jtag_error = ERROR_OK; static const char *jtag_event_strings[] = { - [JTAG_TRST_ASSERTED] = "JTAG controller reset (TLR or TRST)", + [JTAG_TRST_ASSERTED] = "TAP reset", + [JTAG_TAP_EVENT_SETUP] = "TAP setup", [JTAG_TAP_EVENT_ENABLE] = "TAP enabled", - [JTAG_TAP_EVENT_POST_RESET] = "post reset", [JTAG_TAP_EVENT_DISABLE] = "TAP disabled", }; @@ -93,6 +93,8 @@ static int jtag_verify = 1; /* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */ static int jtag_nsrst_delay = 0; /* default to no nSRST delay */ static int jtag_ntrst_delay = 0; /* default to no nTRST delay */ +static int jtag_nsrst_assert_width = 0; /* width of assertion */ +static int jtag_ntrst_assert_width = 0; /* width of assertion */ typedef struct jtag_event_callback_s { @@ -446,7 +448,7 @@ void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { assert(state != TAP_RESET); - + jtag_prelude(state); int retval; @@ -458,7 +460,7 @@ void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { assert(state != TAP_RESET); - + jtag_prelude(state); int retval; @@ -471,7 +473,6 @@ void jtag_add_dr_out(jtag_tap_t* tap, tap_state_t end_state) { assert(end_state != TAP_RESET); - assert(end_state != TAP_INVALID); cmd_queue_cur_state = end_state; @@ -486,9 +487,9 @@ void jtag_add_tlr(void) jtag_prelude(TAP_RESET); jtag_set_error(interface_jtag_add_tlr()); - jtag_notify_reset(); - + /* NOTE: order here matches TRST path in jtag_add_reset() */ jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + jtag_notify_event(JTAG_TRST_ASSERTED); } void jtag_add_pathmove(int num_states, const tap_state_t *path) @@ -662,7 +663,11 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) if (jtag_srst != new_srst) { jtag_srst = new_srst; if (jtag_srst) + { LOG_DEBUG("SRST line asserted"); + if (jtag_nsrst_assert_width) + jtag_add_sleep(jtag_nsrst_assert_width * 1000); + } else { LOG_DEBUG("SRST line released"); if (jtag_nsrst_delay) @@ -684,22 +689,22 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) } 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); + if (jtag_ntrst_assert_width) + jtag_add_sleep(jtag_ntrst_assert_width * 1000); } else { LOG_DEBUG("TRST line released"); if (jtag_ntrst_delay) jtag_add_sleep(jtag_ntrst_delay * 1000); - jtag_notify_reset(); + /* We just asserted nTRST, so we're now in TAP_RESET. + * Inform possible listeners about this, now that + * JTAG instructions and data can be shifted. This + * sequence must match jtag_add_tlr(). + */ + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + jtag_notify_event(JTAG_TRST_ASSERTED); } } } @@ -823,8 +828,6 @@ static int jtag_reset_callback(enum jtag_event event, void *priv) { jtag_tap_t *tap = priv; - LOG_DEBUG("-"); - if (event == JTAG_TRST_ASSERTED) { tap->enabled = !tap->disabled_after_reset; @@ -842,13 +845,21 @@ void jtag_sleep(uint32_t us) alive_sleep(us/1000); } -/// maximum number of JTAG devices expected in the chain +/* Maximum number of enabled JTAG devices we expect in the scan chain, + * plus one (to detect garbage at the end). Devices that don't support + * IDCODE take up fewer bits, possibly allowing a few more devices. + */ #define JTAG_MAX_CHAIN_SIZE 20 #define EXTRACT_MFG(X) (((X) & 0xffe) >> 1) #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12) #define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28) +/* A reserved manufacturer ID is used in END_OF_CHAIN_FLAG, so we + * know that no valid TAP will have it as an IDCODE value. + */ +#define END_OF_CHAIN_FLAG 0x000000ff + static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode) { scan_field_t field = { @@ -860,7 +871,7 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod // initialize to the end of chain ID value for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++) - buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF); + buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG); jtag_add_plain_dr_scan(1, &field, TAP_DRPAUSE); jtag_add_tlr(); @@ -882,8 +893,9 @@ static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count) * the scan is not valid */ if (zero_check == 0x00 || one_check == 0xff) { - LOG_ERROR("JTAG communication failure: check connection, " - "JTAG interface, target power etc."); + LOG_ERROR("JTAG scan chain interrogation failed: all %s", + (zero_check == 0x00) ? "zeroes" : "ones"); + LOG_ERROR("Check JTAG interface, timings, target power, etc."); return false; } return true; @@ -904,7 +916,12 @@ static void jtag_examine_chain_display(enum log_levels level, const char *msg, static bool jtag_idcode_is_final(uint32_t idcode) { - return idcode == 0x000000FF || idcode == 0xFFFFFFFF; + /* + * Some devices, such as AVR8, will output all 1's instead + * of TDI input value at end of chain. Allow those values + * instead of failing. + */ + return idcode == END_OF_CHAIN_FLAG || idcode == 0xFFFFFFFF; } /** @@ -912,8 +929,9 @@ static bool jtag_idcode_is_final(uint32_t idcode) * all as expected, but a single JTAG device requires only 64 bits to be * read back correctly. This can help identify and diagnose problems * with the JTAG chain earlier, gives more helpful/explicit error messages. + * Returns TRUE iff garbage was found. */ -static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max) +static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max) { bool triggered = false; for (; count < max - 31; count += 32) @@ -926,35 +944,29 @@ static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned ma count, (unsigned int)idcode); triggered = true; } + return triggered; } static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap) { - if (0 == tap->expected_ids_cnt) - { - /// @todo Enable LOG_INFO to ask for reports about unknown TAP IDs. -#if 0 - LOG_INFO("Uknown JTAG TAP ID: 0x%08x", tap->idcode) - LOG_INFO("Please report the chip name and reported ID code to the openocd project"); -#endif + /* ignore expected BYPASS codes; warn otherwise */ + if (0 == tap->expected_ids_cnt && !tap->idcode) return true; - } /* Loop over the expected identification codes and test for a match */ uint8_t ii; for (ii = 0; ii < tap->expected_ids_cnt; ii++) { if (tap->idcode == tap->expected_ids[ii]) - break; - } + return true; - /* If none of the expected ids matched, log an error */ - if (ii != tap->expected_ids_cnt) - { - LOG_DEBUG("JTAG Tap/device matched"); - return true; + /* treat "-expected-id 0" as a "don't-warn" wildcard */ + if (0 == tap->expected_ids[ii]) + return true; } - jtag_examine_chain_display(LOG_LVL_ERROR, "got", + + /* If none of the expected ids matched, warn */ + jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED", tap->dotted_name, tap->idcode); for (ii = 0; ii < tap->expected_ids_cnt; ii++) { @@ -968,14 +980,17 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap) } /* Try to examine chain layout according to IEEE 1149.1 §12 + * This is called a "blind interrogation" of the scan chain. */ static int jtag_examine_chain(void) { uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; - unsigned device_count = 0; + unsigned bit_count; + /* DR scan to collect BYPASS or IDCODE register contents. + * Then make sure the scan data has both ones and zeroes. + */ jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE); - if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE)) return ERROR_JTAG_INIT_FAILED; @@ -987,7 +1002,7 @@ static int jtag_examine_chain(void) return ERROR_JTAG_INIT_FAILED; } - for (unsigned bit_count = 0; + for (bit_count = 0; tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31; tap = jtag_tap_next_enabled(tap)) { @@ -996,7 +1011,8 @@ static int jtag_examine_chain(void) if ((idcode & 1) == 0) { /* LSB must not be 0, this indicates a device in bypass */ - LOG_WARNING("Tap/Device does not have IDCODE"); + LOG_WARNING("TAP %s does not have IDCODE", + tap->dotted_name); idcode = 0; tap->hasidcode = false; @@ -1004,71 +1020,71 @@ static int jtag_examine_chain(void) } else { + /* Friendly devices support IDCODE */ tap->hasidcode = true; - - /* - * End of chain (invalid manufacturer ID) some devices, such - * as AVR will output all 1's instead of TDI input value at - * end of chain. - */ - if (jtag_idcode_is_final(idcode)) - { - jtag_examine_chain_end(idcode_buffer, - bit_count + 32, JTAG_MAX_CHAIN_SIZE * 32); - break; - } - jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", - tap ? tap->dotted_name : "(not-named)", - idcode); + tap->dotted_name, idcode); bit_count += 32; } - device_count++; - if (!tap) - continue; - tap->idcode = idcode; - // ensure the TAP ID does matches what was expected + /* ensure the TAP ID matches what was expected */ if (!jtag_examine_chain_match_tap(tap)) return ERROR_JTAG_INIT_FAILED; } - /* see if number of discovered devices matches configuration */ - if (device_count != jtag_tap_count_enabled()) - { - LOG_ERROR("number of discovered devices in JTAG chain (%i) " - "does not match (enabled) configuration (%i), total taps: %d", - device_count, jtag_tap_count_enabled(), jtag_tap_count()); - LOG_ERROR("check the config file and ensure proper JTAG communication" - " (connections, speed, ...)"); + /* Fail if too many TAPs were enabled for us to verify them all. */ + if (tap) { + LOG_ERROR("Too many TAPs enabled; '%s' ignored.", + tap->dotted_name); + return ERROR_JTAG_INIT_FAILED; + } + + /* After those IDCODE or BYPASS register values should be + * only the data we fed into the scan chain. + */ + if (jtag_examine_chain_end(idcode_buffer, bit_count, + 8 * sizeof(idcode_buffer))) { + LOG_ERROR("double-check your JTAG setup (interface, " + "speed, TAPs, ...)"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } -int jtag_validate_chain(void) +/* + * Validate the date loaded by entry to the Capture-IR state, to help + * find errors related to scan chain configuration (wrong IR lengths) + * or communication. + * + * Entry state can be anything. On non-error exit, all TAPs are in + * bypass mode. On error exits, the scan chain is reset. + */ +static int jtag_validate_ircapture(void) { jtag_tap_t *tap; int total_ir_length = 0; uint8_t *ir_test = NULL; scan_field_t field; + int val; int chain_pos = 0; + int retval; - tap = NULL; - total_ir_length = 0; - for (;;) { - tap = jtag_tap_next_enabled(tap); - if (tap == NULL) { - break; - } - total_ir_length += tap->ir_length; - } + for (tap = NULL, total_ir_length = 0; + (tap = jtag_tap_next_enabled(tap)) != NULL; + total_ir_length += tap->ir_length) + continue; + /* increase length to add 2 bit sentinel after scan */ total_ir_length += 2; + ir_test = malloc(CEIL(total_ir_length, 8)); + if (ir_test == NULL) + return ERROR_FAIL; + + /* after this scan, all TAPs will capture BYPASS instructions */ buf_set_ones(ir_test, total_ir_length); field.tap = NULL; @@ -1076,50 +1092,60 @@ int jtag_validate_chain(void) field.out_value = ir_test; field.in_value = ir_test; + jtag_add_plain_ir_scan(1, &field, TAP_IDLE); - jtag_add_plain_ir_scan(1, &field, TAP_IRPAUSE); - jtag_add_tlr(); - - int retval; + LOG_DEBUG("IR capture validation scan"); retval = jtag_execute_queue(); if (retval != ERROR_OK) - return retval; + goto done; tap = NULL; chain_pos = 0; - int val; + for (;;) { tap = jtag_tap_next_enabled(tap); if (tap == NULL) { break; } - val = buf_get_u32(ir_test, chain_pos, 2); - /* 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); - free(cbuf); - free(ir_test); - return ERROR_JTAG_INIT_FAILED; + /* Validate the two LSBs, which must be 01 per JTAG spec. + * REVISIT we might be able to verify some MSBs too, using + * ircapture/irmask attributes. + */ + val = buf_get_u32(ir_test, chain_pos, tap->ir_length); + if ((val & 0x3) != 1) { + LOG_ERROR("%s: IR capture error; saw 0x%0*x not 0x..1", + jtag_tap_name(tap), + (tap->ir_length + 7) / tap->ir_length, + val); + + retval = ERROR_JTAG_INIT_FAILED; + goto done; } + LOG_DEBUG("%s: IR capture 0x%0*x", jtag_tap_name(tap), + (tap->ir_length + 7) / tap->ir_length, val); chain_pos += tap->ir_length; } + /* verify the '11' sentinel we wrote is returned at the end */ val = buf_get_u32(ir_test, chain_pos, 2); if (val != 0x3) { char *cbuf = buf_to_str(ir_test, total_ir_length, 16); - LOG_ERROR("Could not validate end of JTAG scan chain, IR mismatch, scan returned 0x%s. pos=%d expected 0x3 got %0x", cbuf, chain_pos, val); + + LOG_ERROR("IR capture error at bit %d, saw 0x%s not 0x...3", + chain_pos, cbuf); free(cbuf); - free(ir_test); - return ERROR_JTAG_INIT_FAILED; + retval = ERROR_JTAG_INIT_FAILED; } +done: free(ir_test); - - return ERROR_OK; + if (retval != ERROR_OK) { + jtag_add_tlr(); + jtag_execute_queue(); + } + return retval; } @@ -1127,6 +1153,7 @@ void jtag_tap_init(jtag_tap_t *tap) { assert(0 != tap->ir_length); + /// @todo fix, this allocates one byte per bit for all three fields! tap->expected = malloc(tap->ir_length); tap->expected_mask = malloc(tap->ir_length); tap->cur_instr = malloc(tap->ir_length); @@ -1144,7 +1171,8 @@ void jtag_tap_init(jtag_tap_t *tap) LOG_DEBUG("Created Tap: %s @ abs position %d, " "irlen %d, capture: 0x%x mask: 0x%x", tap->dotted_name, tap->abs_chain_position, tap->ir_length, - (unsigned int)(tap->ir_capture_value), (unsigned int)(tap->ir_capture_mask)); + (unsigned) tap->ir_capture_value, + (unsigned) tap->ir_capture_mask); jtag_tap_add(tap); } @@ -1153,6 +1181,7 @@ void jtag_tap_free(jtag_tap_t *tap) jtag_unregister_event_callback(&jtag_reset_callback, tap); /// @todo is anything missing? no memory leaks please + free((void *)tap->expected); free((void *)tap->expected_ids); free((void *)tap->chip); free((void *)tap->tapname); @@ -1201,10 +1230,11 @@ int jtag_interface_init(struct command_context_s *cmd_ctx) return ERROR_OK; } -static int jtag_init_inner(struct command_context_s *cmd_ctx) +int jtag_init_inner(struct command_context_s *cmd_ctx) { jtag_tap_t *tap; int retval; + bool issue_setup = true; LOG_DEBUG("Init JTAG chain"); @@ -1221,14 +1251,22 @@ static int jtag_init_inner(struct command_context_s *cmd_ctx) /* examine chain first, as this could discover the real chain layout */ if (jtag_examine_chain() != ERROR_OK) { - LOG_ERROR("trying to validate configured JTAG chain anyway..."); + LOG_ERROR("Trying to use configured scan chain anyway..."); + issue_setup = false; } - if (jtag_validate_chain() != ERROR_OK) + if (jtag_validate_ircapture() != ERROR_OK) { - LOG_WARNING("Could not validate JTAG chain, continuing anyway..."); + LOG_WARNING("Errors during IR capture, continuing anyway..."); + issue_setup = false; } + if (issue_setup) + jtag_notify_event(JTAG_TAP_EVENT_SETUP); + else + LOG_WARNING("Bypassing JTAG setup events due to errors"); + + return ERROR_OK; } @@ -1296,11 +1334,11 @@ int jtag_init(struct command_context_s *cmd_ctx) int retval; if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK) return retval; - if (jtag_init_inner(cmd_ctx) == ERROR_OK) - { - return ERROR_OK; - } - return jtag_init_reset(cmd_ctx); + + if (Jim_Eval_Named(interp, "jtag_init", __FILE__, __LINE__) != JIM_OK) + return ERROR_FAIL; + + return ERROR_OK; } unsigned jtag_get_speed_khz(void) @@ -1462,3 +1500,21 @@ unsigned jtag_get_ntrst_delay(void) { return jtag_ntrst_delay; } + + +void jtag_set_nsrst_assert_width(unsigned delay) +{ + jtag_nsrst_assert_width = delay; +} +unsigned jtag_get_nsrst_assert_width(void) +{ + return jtag_nsrst_assert_width; +} +void jtag_set_ntrst_assert_width(unsigned delay) +{ + jtag_ntrst_assert_width = delay; +} +unsigned jtag_get_ntrst_assert_width(void) +{ + return jtag_ntrst_assert_width; +}