summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-10-26 00:36:03 -0700
committerDavid Brownell <dbrownell@users.sourceforge.net>2009-10-26 00:36:03 -0700
commit6cb1d10cdad509939e3decf089e08c289d85d5cf (patch)
treead1b0c30d9b95c0ee34594a0f538bd68133efe2e
parent0cac8b67be5c6f6f5b2bc3a86f78d4d02e364792 (diff)
downloadopenocd+libswd-6cb1d10cdad509939e3decf089e08c289d85d5cf.tar.gz
openocd+libswd-6cb1d10cdad509939e3decf089e08c289d85d5cf.tar.bz2
openocd+libswd-6cb1d10cdad509939e3decf089e08c289d85d5cf.tar.xz
openocd+libswd-6cb1d10cdad509939e3decf089e08c289d85d5cf.zip
JTAG: simple autoprobing
This patch adds basic autoprobing support for the JTAG scan chains which cooperate. To use, you can invoke OpenOCD with just: - interface spec: "-f interface/...cfg" - possibly with "-c 'reset_config ...'" for SRST/TRST - possibly with "-c 'jtag_khz ...'" for the JTAG clock Then set up config files matching the reported TAPs. It doesn't declare targets ... just TAPs. So facilities above the JTAG and SVF/XSVF levels won't be available without a real config; this is almost purely a way to generate diagnostics. Autoprobe was successful with most boards I tested, except ones incorporating C55x DSPs (which don't cooperate with this scheme for IR length autodetection). Here's what one multi-TAP chip reported, with the "Warn:" prefixes removed: clock speed 500 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified The patch tweaks IR setup a bit, so we can represent TAPs with undeclared IR length. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-rw-r--r--TODO9
-rw-r--r--src/jtag/core.c114
2 files changed, 109 insertions, 14 deletions
diff --git a/TODO b/TODO
index 6f9c7494..f567a82f 100644
--- a/TODO
+++ b/TODO
@@ -55,8 +55,10 @@ directly in minidriver API for better embedded host performance.
The following tasks have been suggested for adding new core JTAG support:
-- autodetect devices present on the scan chain
- - implement 'discover_taps' command
+- Improve autodetection of TAPs by supporting tcl escape procedures that
+ can configure discovered TAPs based on IDCODE value ... they could:
+ - Remove guessing for irlen
+ - Allow non-default irmask/ircapture values
- SPI/UART emulation:
- (ab)use bit-banging JTAG interfaces to emulate SPI/UART
- allow SPI to program flash, MCUs, etc.
@@ -94,6 +96,8 @@ interface support:
- FT2232 (libftdi):
- make performance comparable to alternatives (on Win32, D2XX is faster)
- make usability comparable to alternatives
+- Autodetect USB based adapters; this should be easy on Linux. If there's
+ more than one, list the options; otherwise, just select that one.
The following tasks have been suggested for adding new JTAG interfaces:
@@ -133,6 +137,7 @@ Once the above are completed:
@section thelisttargets Target Support
+- Many common ARM cores could be autodetected using IDCODE
- general layer cleanup: @par
https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html
- regression: "reset halt" between 729(works) and 788(fails): @par
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 08cfe436..8bb45bcd 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -890,6 +890,9 @@ void jtag_sleep(uint32_t us)
*/
#define END_OF_CHAIN_FLAG 0x000000ff
+/* a larger IR length than we ever expect to autoprobe */
+#define JTAG_IRLEN_MAX 60
+
static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
{
scan_field_t field = {
@@ -1027,6 +1030,8 @@ static int jtag_examine_chain(void)
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
unsigned bit_count;
int retval;
+ int tapcount = 0;
+ bool autoprobe = false;
/* DR scan to collect BYPASS or IDCODE register contents.
* Then make sure the scan data has both ones and zeroes.
@@ -1040,11 +1045,9 @@ static int jtag_examine_chain(void)
/* point at the 1st tap */
jtag_tap_t *tap = jtag_tap_next_enabled(NULL);
- if (tap == NULL)
- {
- LOG_ERROR("JTAG: No taps enabled?");
- return ERROR_JTAG_INIT_FAILED;
- }
+
+ if (!tap)
+ autoprobe = true;
for (bit_count = 0;
tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
@@ -1086,6 +1089,59 @@ static int jtag_examine_chain(void)
return ERROR_JTAG_INIT_FAILED;
}
+ /* if autoprobing, the tap list is still empty ... populate it! */
+ while (autoprobe && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31) {
+ uint32_t idcode;
+ char buf[12];
+
+ /* Is there another TAP? */
+ idcode = buf_get_u32(idcode_buffer, bit_count, 32);
+ if (jtag_idcode_is_final(idcode))
+ break;
+
+ /* Default everything in this TAP except IR length.
+ *
+ * REVISIT create a jtag_alloc(chip, tap) routine, and
+ * share it with jim_newtap_cmd().
+ */
+ tap = calloc(1, sizeof *tap);
+ if (!tap)
+ return ERROR_FAIL;
+
+ sprintf(buf, "auto%d", tapcount++);
+ tap->chip = strdup(buf);
+ tap->tapname = strdup("tap");
+
+ sprintf(buf, "%s.%s", tap->chip, tap->tapname);
+ tap->dotted_name = strdup(buf);
+
+ /* tap->ir_length == 0 ... signifying irlen autoprobe */
+ tap->ir_capture_mask = 0x03;
+ tap->ir_capture_value = 0x01;
+
+ tap->enabled = true;
+
+ if ((idcode & 1) == 0) {
+ bit_count += 1;
+ tap->hasidcode = false;
+ } else {
+ bit_count += 32;
+ tap->hasidcode = true;
+ tap->idcode = idcode;
+
+ tap->expected_ids_cnt = 1;
+ tap->expected_ids = malloc(sizeof(uint32_t));
+ tap->expected_ids[0] = idcode;
+ }
+
+ LOG_WARNING("AUTO %s - use \"jtag newtap "
+ "%s %s -expected-id 0x%8.8" PRIx32 " ...\"",
+ tap->dotted_name, tap->chip, tap->tapname,
+ tap->idcode);
+
+ jtag_tap_init(tap);
+ }
+
/* After those IDCODE or BYPASS register values should be
* only the data we fed into the scan chain.
*/
@@ -1120,10 +1176,13 @@ static int jtag_validate_ircapture(void)
int chain_pos = 0;
int retval;
+ /* when autoprobing, accomodate huge IR lengths */
for (tap = NULL, total_ir_length = 0;
(tap = jtag_tap_next_enabled(tap)) != NULL;
- total_ir_length += tap->ir_length)
- continue;
+ total_ir_length += tap->ir_length) {
+ if (tap->ir_length == 0)
+ total_ir_length += JTAG_IRLEN_MAX;
+ }
/* increase length to add 2 bit sentinel after scan */
total_ir_length += 2;
@@ -1156,6 +1215,25 @@ static int jtag_validate_ircapture(void)
break;
}
+ /* If we're autoprobing, guess IR lengths. They must be at
+ * least two bits. Guessing will fail if (a) any TAP does
+ * not conform to the JTAG spec; or (b) when the upper bits
+ * captured from some conforming TAP are nonzero.
+ *
+ * REVISIT alternative approach: escape to some tcl code
+ * which could provide more knowledge, based on IDCODE; and
+ * only guess when that has no success.
+ */
+ if (tap->ir_length == 0) {
+ tap->ir_length = 2;
+ while ((val = buf_get_u32(ir_test, chain_pos,
+ tap->ir_length + 1)) == 1) {
+ tap->ir_length++;
+ }
+ LOG_WARNING("AUTO %s - use \"... -irlen %d\"",
+ jtag_tap_name(tap), tap->ir_length);
+ }
+
/* Validate the two LSBs, which must be 01 per JTAG spec.
*
* Or ... more bits could be provided by TAP declaration.
@@ -1207,9 +1285,8 @@ void jtag_tap_init(jtag_tap_t *tap)
unsigned ir_len_bits;
unsigned ir_len_bytes;
- assert(0 != tap->ir_length);
-
- ir_len_bits = tap->ir_length;
+ /* if we're autoprobing, cope with potentially huge ir_length */
+ ir_len_bits = tap->ir_length ? : JTAG_IRLEN_MAX;
ir_len_bytes = CEIL(ir_len_bits, 8);
tap->expected = calloc(1, ir_len_bytes);
@@ -1302,8 +1379,21 @@ int jtag_init_inner(struct command_context_s *cmd_ctx)
tap = jtag_tap_next_enabled(NULL);
if (tap == NULL) {
- LOG_ERROR("There are no enabled taps?");
- return ERROR_JTAG_INIT_FAILED;
+ /* Once JTAG itself is properly set up, and the scan chain
+ * isn't absurdly large, IDCODE autoprobe should work fine.
+ *
+ * But ... IRLEN autoprobe can fail even on systems which
+ * are fully conformant to JTAG. Also, JTAG setup can be
+ * quite finicky on some systems.
+ *
+ * REVISIT: if TAP autoprobe works OK, then in many cases
+ * we could escape to tcl code and set up targets based on
+ * the TAP's IDCODE values.
+ */
+ LOG_WARNING("There are no enabled taps. "
+ "AUTO PROBING MIGHT NOT WORK!!");
+
+ /* REVISIT default clock will often be too fast ... */
}
jtag_add_tlr();