/***************************************************************************
- * 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 *
static const char *jtag_event_strings[] =
{
[JTAG_TRST_ASSERTED] = "TAP reset",
+ [JTAG_TAP_EVENT_SETUP] = "TAP setup",
[JTAG_TAP_EVENT_ENABLE] = "TAP enabled",
- [JTAG_TAP_EVENT_POST_RESET] = "TAP post reset",
[JTAG_TAP_EVENT_DISABLE] = "TAP disabled",
};
/*
* JTAG adapters must initialize with TRST and SRST de-asserted
- * (they're negative logic, so that means *high*)
+ * (they're negative logic, so that means *high*). But some
+ * hardware doesn't necessarily work that way ... so set things
+ * up so that jtag_init() always forces that state.
*/
-static int jtag_trst = 0;
-static int jtag_srst = 0;
+static int jtag_trst = -1;
+static int jtag_srst = -1;
/**
* List all TAPs that have been created.
return temp;
}
+/************/
+
+static bool jtag_poll = 1;
+
+bool is_jtag_poll_safe(void)
+{
+ /* Polling can be disabled explicitly with set_enabled(false).
+ * It is also implicitly disabled while TRST is active and
+ * while SRST is gating the JTAG clock.
+ */
+ if (!jtag_poll || jtag_trst != 0)
+ return false;
+ return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING);
+}
+
+bool jtag_poll_get_enabled(void)
+{
+ return jtag_poll;
+}
+
+void jtag_poll_set_enabled(bool value)
+{
+ jtag_poll = value;
+}
+
+/************/
jtag_tap_t *jtag_all_taps(void)
{
/* NOTE: order here matches TRST path in jtag_add_reset() */
jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
- jtag_notify_reset();
+ jtag_notify_event(JTAG_TRST_ASSERTED);
}
void jtag_add_pathmove(int num_states, const tap_state_t *path)
* sequence must match jtag_add_tlr().
*/
jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
- jtag_notify_reset();
+ jtag_notify_event(JTAG_TRST_ASSERTED);
}
}
}
}
/* if there wasn't a single non-zero bit or if all bits were one,
- * the scan is not valid */
+ * the scan is not valid. We wrote a mix of both values; either
+ *
+ * - There's a hardware issue (almost certainly):
+ * + all-zeroes can mean a target stuck in JTAG reset
+ * + all-ones tends to mean no target
+ * - The scan chain is WAY longer than we can handle, *AND* either
+ * + there are several hundreds of TAPs in bypass, or
+ * + at least a few dozen TAPs all have an all-ones IDCODE
+ */
if (zero_check == 0x00 || one_check == 0xff)
{
LOG_ERROR("JTAG scan chain interrogation failed: all %s",
{
if (tap->idcode == tap->expected_ids[ii])
return true;
+
+ /* treat "-expected-id 0" as a "don't-warn" wildcard */
+ if (0 == tap->expected_ids[ii])
+ return true;
}
- /* If none of the expected ids matched, log an error */
- jtag_examine_chain_display(LOG_LVL_ERROR, "UNEXPECTED",
+ /* 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++)
{
{
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
unsigned bit_count;
+ int retval;
/* 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);
+ retval = jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
+ if (retval != ERROR_OK)
+ return retval;
if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE))
return ERROR_JTAG_INIT_FAILED;
if ((idcode & 1) == 0)
{
- /* LSB must not be 0, this indicates a device in bypass */
+ /* Zero for LSB indicates a device in bypass */
LOG_WARNING("TAP %s does not have IDCODE",
tap->dotted_name);
idcode = 0;
{
/* Friendly devices support IDCODE */
tap->hasidcode = true;
- jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found",
+ jtag_examine_chain_display(LOG_LVL_INFO,
+ "tap/device found",
tap->dotted_name, idcode);
bit_count += 32;
}
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;
+ retval = ERROR_JTAG_INIT_SOFT_FAIL;
}
/* Fail if too many TAPs were enabled for us to verify them all. */
if (jtag_examine_chain_end(idcode_buffer, bit_count,
8 * sizeof(idcode_buffer))) {
LOG_ERROR("double-check your JTAG setup (interface, "
- "speed, TAPs, ...)");
+ "speed, missing TAPs, ...)");
return ERROR_JTAG_INIT_FAILED;
}
- return ERROR_OK;
+ /* Return success or, for backwards compatibility if only
+ * some IDCODE values mismatched, a soft/continuable fault.
+ */
+ return retval;
}
/*
* 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)
{
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;
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) {
}
/* 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.
+ *
+ * Or ... more bits could be provided by TAP declaration.
+ * Plus, some taps (notably in i.MX series chips) violate
+ * this part of the JTAG spec, so their capture mask/value
+ * attributes might disable this test.
*/
- val = buf_get_u32(ir_test, chain_pos, 2);
- if (val != 1) {
- char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
-
- LOG_ERROR("%s: IR capture error; saw 0x%s not 0x..1",
- jtag_tap_name(tap), cbuf);
-
- /* Fail only if we have IDCODE for this device.
- * REVISIT -- why not fail-always?
- */
- if (tap->hasidcode) {
- free(cbuf);
- free(ir_test);
- return ERROR_JTAG_INIT_FAILED;
- }
+ val = buf_get_u32(ir_test, chain_pos, tap->ir_length);
+ if ((val & tap->ir_capture_mask) != tap->ir_capture_value) {
+ LOG_ERROR("%s: IR capture error; saw 0x%0*x not 0x%0*x",
+ jtag_tap_name(tap),
+ (tap->ir_length + 7) / tap->ir_length,
+ val,
+ (tap->ir_length + 7) / tap->ir_length,
+ tap->ir_capture_value);
+
+ 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;
}
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;
}
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");
if ((retval = jtag_execute_queue()) != ERROR_OK)
return retval;
- /* examine chain first, as this could discover the real chain layout */
- if (jtag_examine_chain() != ERROR_OK)
- {
+ /* Examine DR values first. This discovers problems which will
+ * prevent communication ... hardware issues like TDO stuck, or
+ * configuring the wrong number of (enabled) TAPs.
+ */
+ retval = jtag_examine_chain();
+ switch (retval) {
+ case ERROR_OK:
+ /* complete success */
+ break;
+ case ERROR_JTAG_INIT_SOFT_FAIL:
+ /* For backward compatibility reasons, try coping with
+ * configuration errors involving only ID mismatches.
+ * We might be able to talk to the devices.
+ */
LOG_ERROR("Trying to use configured scan chain anyway...");
+ issue_setup = false;
+ break;
+ default:
+ /* some hard error; already issued diagnostics */
+ return retval;
}
- if (jtag_validate_ircapture() != ERROR_OK)
- {
- LOG_WARNING("Errors during IR capture, continuing anyway...");
- }
+ /* Now look at IR values. Problems here will prevent real
+ * communication. They mostly mean that the IR length is
+ * wrong ... or that the IR capture value is wrong. (The
+ * latter is uncommon, but easily worked around: provide
+ * ircapture/irmask values during TAP setup.)
+ */
+ retval = jtag_validate_ircapture();
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (issue_setup)
+ jtag_notify_event(JTAG_TAP_EVENT_SETUP);
+ else
+ LOG_WARNING("Bypassing JTAG setup events due to errors");
+
return ERROR_OK;
}
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);
+
+ /* guard against oddball hardware: force resets to be inactive */
+ jtag_add_reset(0, 0);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ return retval;
+
+ if (Jim_Eval_Named(interp, "jtag_init", __FILE__, __LINE__) != JIM_OK)
+ return ERROR_FAIL;
+
+ return ERROR_OK;
}
unsigned jtag_get_speed_khz(void)