scan_field_t -> struct scan_field
[fw/openocd] / src / jtag / core.c
index 3021a10306a5edb62e15061f63799db51fa93b4a..48af0406fe74aa954306014f48d7aeb17fafb211 100644 (file)
@@ -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  *
@@ -43,8 +43,8 @@
 /// The number of JTAG queue flushes (for profiling and debugging purposes).
 static int jtag_flush_queue_count;
 
-static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state),
-               int in_num_fields, scan_field_t *in_fields, tap_state_t state);
+static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const struct scan_field *in_fields, tap_state_t state),
+               int in_num_fields, struct scan_field *in_fields, tap_state_t state);
 
 /**
  * The jtag_error variable is set when an error occurs while executing
@@ -60,22 +60,25 @@ 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_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.
  */
-static jtag_tap_t *__jtag_all_taps = NULL;
+static struct jtag_tap *__jtag_all_taps = NULL;
 /**
  * The number of TAPs in the __jtag_all_taps list, used to track the
  * assigned chain position to new TAPs
@@ -92,6 +95,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
 {
@@ -132,8 +137,34 @@ int jtag_error_clear(void)
        return temp;
 }
 
+/************/
+
+static bool jtag_poll = 1;
 
-jtag_tap_t *jtag_all_taps(void)
+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;
+}
+
+/************/
+
+struct jtag_tap *jtag_all_taps(void)
 {
        return __jtag_all_taps;
 };
@@ -145,7 +176,7 @@ unsigned jtag_tap_count(void)
 
 unsigned jtag_tap_count_enabled(void)
 {
-       jtag_tap_t *t = jtag_all_taps();
+       struct jtag_tap *t = jtag_all_taps();
        unsigned n = 0;
        while (t)
        {
@@ -157,20 +188,20 @@ unsigned jtag_tap_count_enabled(void)
 }
 
 /// Append a new TAP to the chain of all taps.
-void jtag_tap_add(struct jtag_tap_s *t)
+void jtag_tap_add(struct jtag_tap *t)
 {
        t->abs_chain_position = jtag_num_taps++;
 
-       jtag_tap_t **tap = &__jtag_all_taps;
+       struct jtag_tap **tap = &__jtag_all_taps;
        while (*tap != NULL)
                tap = &(*tap)->next_tap;
        *tap = t;
 }
 
 /* returns a pointer to the n-th device in the scan chain */
-static inline jtag_tap_t *jtag_tap_by_position(unsigned n)
+static inline struct jtag_tap *jtag_tap_by_position(unsigned n)
 {
-       jtag_tap_t *t = jtag_all_taps();
+       struct jtag_tap *t = jtag_all_taps();
 
        while (t && n-- > 0)
                t = t->next_tap;
@@ -178,10 +209,10 @@ static inline jtag_tap_t *jtag_tap_by_position(unsigned n)
        return t;
 }
 
-jtag_tap_t *jtag_tap_by_string(const char *s)
+struct jtag_tap *jtag_tap_by_string(const char *s)
 {
        /* try by name first */
-       jtag_tap_t *t = jtag_all_taps();
+       struct jtag_tap *t = jtag_all_taps();
 
        while (t)
        {
@@ -207,10 +238,10 @@ jtag_tap_t *jtag_tap_by_string(const char *s)
        return t;
 }
 
-jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
+struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
 {
        const char *cp = Jim_GetString(o, NULL);
-       jtag_tap_t *t = cp ? jtag_tap_by_string(cp) : NULL;
+       struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL;
        if (NULL == cp)
                cp = "(unknown)";
        if (NULL == t)
@@ -218,7 +249,7 @@ jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
        return t;
 }
 
-jtag_tap_t* jtag_tap_next_enabled(jtag_tap_t* p)
+struct jtag_tap* jtag_tap_next_enabled(struct jtag_tap* p)
 {
        p = p ? p->next_tap : jtag_all_taps();
        while (p)
@@ -230,7 +261,7 @@ jtag_tap_t* jtag_tap_next_enabled(jtag_tap_t* p)
        return NULL;
 }
 
-const char *jtag_tap_name(const jtag_tap_t *tap)
+const char *jtag_tap_name(const struct jtag_tap *tap)
 {
        return (tap == NULL) ? "(unknown)" : tap->dotted_name;
 }
@@ -322,12 +353,12 @@ static void jtag_prelude(tap_state_t state)
        cmd_queue_cur_state = state;
 }
 
-void jtag_alloc_in_value32(scan_field_t *field)
+void jtag_alloc_in_value32(struct scan_field *field)
 {
        interface_jtag_alloc_in_value32(field);
 }
 
-void jtag_add_ir_scan_noverify(int in_count, const scan_field_t *in_fields,
+void jtag_add_ir_scan_noverify(int in_count, const struct scan_field *in_fields,
                tap_state_t state)
 {
        jtag_prelude(state);
@@ -337,8 +368,10 @@ void jtag_add_ir_scan_noverify(int in_count, const scan_field_t *in_fields,
 }
 
 
-void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state)
+void jtag_add_ir_scan(int in_num_fields, struct scan_field *in_fields, tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        if (jtag_verify && jtag_verify_capture_ir)
        {
                /* 8 x 32 bit id's is enough for all invocations */
@@ -358,9 +391,11 @@ void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t st
        }
 }
 
-void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields,
+void jtag_add_plain_ir_scan(int in_num_fields, const struct scan_field *in_fields,
                tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        jtag_prelude(state);
 
        int retval = interface_jtag_add_plain_ir_scan(
@@ -380,19 +415,20 @@ void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0,
        interface_jtag_add_callback4(f, data0, data1, data2, data3);
 }
 
-int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits);
+static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value,
+               uint8_t *in_check_mask, int num_bits);
 
 static int jtag_check_value_mask_callback(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
 {
        return jtag_check_value_inner((uint8_t *)data0, (uint8_t *)data1, (uint8_t *)data2, (int)data3);
 }
 
-static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state),
-               int in_num_fields, scan_field_t *in_fields, tap_state_t state)
+static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const struct scan_field *in_fields, tap_state_t state),
+               int in_num_fields, struct scan_field *in_fields, tap_state_t state)
 {
        for (int i = 0; i < in_num_fields; i++)
        {
-               struct scan_field_s *field = &in_fields[i];
+               struct scan_field *field = &in_fields[i];
                field->allocated = 0;
                field->modified = 0;
                if (field->check_value || field->in_value)
@@ -424,7 +460,7 @@ static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const s
        }
 }
 
-void jtag_add_dr_scan_check(int in_num_fields, scan_field_t *in_fields, tap_state_t state)
+void jtag_add_dr_scan_check(int in_num_fields, struct scan_field *in_fields, tap_state_t state)
 {
        if (jtag_verify)
        {
@@ -436,9 +472,11 @@ void jtag_add_dr_scan_check(int in_num_fields, scan_field_t *in_fields, tap_stat
 }
 
 
-void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields,
+void jtag_add_dr_scan(int in_num_fields, const struct scan_field *in_fields,
                tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        jtag_prelude(state);
 
        int retval;
@@ -446,9 +484,11 @@ void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields,
        jtag_set_error(retval);
 }
 
-void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields,
+void jtag_add_plain_dr_scan(int in_num_fields, const struct scan_field *in_fields,
                tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        jtag_prelude(state);
 
        int retval;
@@ -456,10 +496,11 @@ void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields,
        jtag_set_error(retval);
 }
 
-void jtag_add_dr_out(jtag_tap_t* tap,
+void jtag_add_dr_out(struct jtag_tap* tap,
                int num_fields, const int* num_bits, const uint32_t* value,
                tap_state_t end_state)
 {
+       assert(end_state != TAP_RESET);
        assert(end_state != TAP_INVALID);
 
        cmd_queue_cur_state = end_state;
@@ -473,7 +514,10 @@ void jtag_add_tlr(void)
 {
        jtag_prelude(TAP_RESET);
        jtag_set_error(interface_jtag_add_tlr());
+
+       /* 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)
@@ -523,12 +567,14 @@ int jtag_add_statemove(tap_state_t goal_state)
                tap_state_name(goal_state));
 
 
-       if (goal_state == cur_state)
-               ;       /* nothing to do */
-       else if (goal_state == TAP_RESET)
-       {
+       /* If goal is RESET, be paranoid and force that that transition
+        * (e.g. five TCK cycles, TMS high).  Else trust "cur_state".
+        */
+       if (goal_state == TAP_RESET)
                jtag_add_tlr();
-       }
+       else if (goal_state == cur_state)
+               /* nothing to do */ ;
+
        else if (tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state))
        {
                unsigned tms_bits  = tap_get_tms_path(cur_state, goal_state);
@@ -647,7 +693,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)
@@ -669,20 +719,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);
+
+                       /* 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);
                }
        }
 }
@@ -711,7 +763,8 @@ void jtag_add_sleep(uint32_t us)
        jtag_set_error(interface_jtag_add_sleep(us));
 }
 
-int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits)
+static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value,
+               uint8_t *in_check_mask, int num_bits)
 {
        int retval = ERROR_OK;
 
@@ -723,44 +776,37 @@ int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *
                compare_failed = buf_cmp(captured, in_check_value, num_bits);
 
        if (compare_failed) {
-               /* An error handler could have caught the failing check
-                * only report a problem when there wasn't a handler, or if the handler
-                * acknowledged the error
-                */
-               /*
-               LOG_WARNING("TAP %s:",
-                                       jtag_tap_name(field->tap));
-                                       */
-               if (compare_failed)
-               {
-                       char *captured_char = buf_to_str(captured, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16);
-                       char *in_check_value_char = buf_to_str(in_check_value, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16);
-
-                       if (in_check_mask)
-                       {
-                               char *in_check_mask_char;
-                               in_check_mask_char = buf_to_str(in_check_mask, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16);
-                               LOG_WARNING("value captured during scan didn't pass the requested check:");
-                               LOG_WARNING("captured: 0x%s check_value: 0x%s check_mask: 0x%s",
-                                                       captured_char, in_check_value_char, in_check_mask_char);
-                               free(in_check_mask_char);
-                       }
-                       else
-                       {
-                               LOG_WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char);
-                       }
+               char *captured_str, *in_check_value_str;
+               int bits = (num_bits > DEBUG_JTAG_IOZ)
+                               ? DEBUG_JTAG_IOZ
+                               : num_bits;
 
-                       free(captured_char);
-                       free(in_check_value_char);
+               /* NOTE:  we've lost diagnostic context here -- 'which tap' */
 
-                       retval = ERROR_JTAG_QUEUE_FAILED;
+               captured_str = buf_to_str(captured, bits, 16);
+               in_check_value_str = buf_to_str(in_check_value, bits, 16);
+
+               LOG_WARNING("Bad value '%s' captured during DR or IR scan:",
+                               captured_str);
+               LOG_WARNING(" check_value: 0x%s", in_check_value_str);
+
+               free(captured_str);
+               free(in_check_value_str);
+
+               if (in_check_mask) {
+                       char *in_check_mask_str;
+
+                       in_check_mask_str = buf_to_str(in_check_mask, bits, 16);
+                       LOG_WARNING(" check_mask: 0x%s", in_check_mask_str);
+                       free(in_check_mask_str);
                }
 
+               retval = ERROR_JTAG_QUEUE_FAILED;
        }
        return retval;
 }
 
-void jtag_check_value_mask(scan_field_t *field, uint8_t *value, uint8_t *mask)
+void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask)
 {
        assert(field->in_value != NULL);
 
@@ -810,9 +856,7 @@ int jtag_execute_queue(void)
 
 static int jtag_reset_callback(enum jtag_event event, void *priv)
 {
-       jtag_tap_t *tap = priv;
-
-       LOG_DEBUG("-");
+       struct jtag_tap *tap = priv;
 
        if (event == JTAG_TRST_ASSERTED)
        {
@@ -831,16 +875,27 @@ 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
+
+/* 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 = {
+       struct scan_field field = {
                        .tap = NULL,
                        .num_bits = num_idcode * 32,
                        .out_value = idcode_buffer,
@@ -849,9 +904,10 @@ 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_RESET);
+       jtag_add_plain_dr_scan(1, &field, TAP_DRPAUSE);
+       jtag_add_tlr();
        return jtag_execute_queue();
 }
 
@@ -867,11 +923,20 @@ static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count)
        }
 
        /* 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 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;
@@ -892,7 +957,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;
 }
 
 /**
@@ -900,55 +970,52 @@ 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)
        {
                uint32_t idcode = buf_get_u32(idcodes, count, 32);
-               // do not trigger the warning if the data looks good
-               if (!triggered && jtag_idcode_is_final(idcode))
+
+               /* do not trigger the warning if the data looks good */
+               if (jtag_idcode_is_final(idcode))
                        continue;
                LOG_WARNING("Unexpected idcode after end of chain: %d 0x%08x",
                                        count, (unsigned int)idcode);
                triggered = true;
        }
+       return triggered;
 }
 
-static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
+static bool jtag_examine_chain_match_tap(const struct jtag_tap *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++)
+       unsigned ii, limit = tap->expected_ids_cnt;
+
+       for (ii = 0; ii < limit; 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++)
+       for (ii = 0; ii < limit; ii++)
        {
                char msg[32];
-               snprintf(msg, sizeof(msg), "expected %hhu of %hhu",
-                               ii + 1, tap->expected_ids_cnt);
+
+               snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, limit);
                jtag_examine_chain_display(LOG_LVL_ERROR, msg,
                                tap->dotted_name, tap->expected_ids[ii]);
        }
@@ -956,33 +1023,43 @@ 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.
  */
-int jtag_examine_chain(void)
+static int jtag_examine_chain(void)
 {
        uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
-       unsigned device_count = 0;
-
-       jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
+       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.
+        */
+       LOG_DEBUG("DR scan interrogation for IDCODE/BYPASS");
+       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;
 
        /* 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;
-       }
+       struct jtag_tap *tap = jtag_tap_next_enabled(NULL);
+
+       if (!tap)
+               autoprobe = true;
 
-       for (unsigned bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
+       for (bit_count = 0;
+                       tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
+                       tap = jtag_tap_next_enabled(tap))
        {
                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");
+                       /* Zero for LSB indicates a device in bypass */
+                       LOG_WARNING("TAP %s does not have IDCODE",
+                                       tap->dotted_name);
                        idcode = 0;
                        tap->hasidcode = false;
 
@@ -990,71 +1067,131 @@ int jtag_examine_chain(void)
                }
                else
                {
-                       /*
-                        * 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);
+                       /* Friendly devices support IDCODE */
+                       tap->hasidcode = true;
+                       jtag_examine_chain_display(LOG_LVL_INFO,
+                                       "tap/device found",
+                                       tap->dotted_name, idcode);
 
                        bit_count += 32;
                }
-               device_count++;
+               tap->idcode = idcode;
+
+               /* ensure the TAP ID matches what was expected */
+               if (!jtag_examine_chain_match_tap(tap))
+                       retval = ERROR_JTAG_INIT_SOFT_FAIL;
+       }
+
+       /* 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;
+       }
+
+       /* 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)
-                       continue;
+                       return ERROR_FAIL;
 
-               tap->idcode = idcode;
+               sprintf(buf, "auto%d", tapcount++);
+               tap->chip = strdup(buf);
+               tap->tapname = strdup("tap");
 
-               // ensure the TAP ID does matches what was expected
-               if (!jtag_examine_chain_match_tap(tap))
-                       return ERROR_JTAG_INIT_FAILED;
+               sprintf(buf, "%s.%s", tap->chip, tap->tapname);
+               tap->dotted_name = strdup(buf);
 
-               tap = jtag_tap_next_enabled(tap);
+               /* 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);
        }
 
-       /* 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, ...)");
+       /* 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, 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;
 }
 
-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;
+       struct jtag_tap *tap;
        int total_ir_length = 0;
        uint8_t *ir_test = NULL;
-       scan_field_t field;
+       struct scan_field 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;
+       /* 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) {
+               if (tap->ir_length == 0)
+                       total_ir_length += JTAG_IRLEN_MAX;
        }
 
+       /* 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;
@@ -1062,81 +1199,128 @@ 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_RESET);
-       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;
+               /* 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.
+                * 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, 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,
+                                       (unsigned) 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;
        }
 
+       /* 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;
 }
 
 
-void jtag_tap_init(jtag_tap_t *tap)
+void jtag_tap_init(struct jtag_tap *tap)
 {
-       assert(0 != tap->ir_length);
+       unsigned ir_len_bits;
+       unsigned ir_len_bytes;
 
-       tap->expected = malloc(tap->ir_length);
-       tap->expected_mask = malloc(tap->ir_length);
-       tap->cur_instr = malloc(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);
 
-       /// @todo cope sanely with ir_length bigger than 32 bits
-       buf_set_u32(tap->expected, 0, tap->ir_length, tap->ir_capture_value);
-       buf_set_u32(tap->expected_mask, 0, tap->ir_length, tap->ir_capture_mask);
-       buf_set_ones(tap->cur_instr, tap->ir_length);
+       tap->expected = calloc(1, ir_len_bytes);
+       tap->expected_mask = calloc(1, ir_len_bytes);
+       tap->cur_instr = malloc(ir_len_bytes);
+
+       /// @todo cope better with ir_length bigger than 32 bits
+       if (ir_len_bits > 32)
+               ir_len_bits = 32;
+
+       buf_set_u32(tap->expected, 0, ir_len_bits, tap->ir_capture_value);
+       buf_set_u32(tap->expected_mask, 0, ir_len_bits, tap->ir_capture_mask);
 
-       // place TAP in bypass mode
+       // TAP will be in bypass mode after jtag_validate_ircapture()
        tap->bypass = 1;
+       buf_set_ones(tap->cur_instr, tap->ir_length);
+
        // register the reset callback for the TAP
        jtag_register_event_callback(&jtag_reset_callback, 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);
 }
 
-void jtag_tap_free(jtag_tap_t *tap)
+void jtag_tap_free(struct jtag_tap *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);
@@ -1185,33 +1369,74 @@ 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;
+       struct jtag_tap *tap;
        int retval;
+       bool issue_setup = true;
 
        LOG_DEBUG("Init JTAG chain");
 
        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();
        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)
-       {
-               LOG_ERROR("trying to validate configured JTAG chain anyway...");
+       /* 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_chain() != ERROR_OK)
-       {
-               LOG_WARNING("Could not validate JTAG chain, 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;
 }
@@ -1237,22 +1462,31 @@ 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 / TLR");
+       LOG_DEBUG("Initializing with hard TRST+SRST reset");
 
-       /* Reset can happen after a power cycle.
-        *
-        * Ideally we would only assert TRST or run TLR before the target reset.
+       /*
+        * This procedure is used by default when OpenOCD triggers a reset.
+        * It's now done through an overridable Tcl "init_reset" wrapper.
         *
-        * However w/srst_pulls_trst, trst is asserted together with the target
-        * reset whether we want it or not.
+        * This started out as a more powerful "get JTAG working" reset than
+        * jtag_init_inner(), applying TRST because some chips won't activate
+        * JTAG without a TRST cycle (presumed to be async, though some of
+        * those chips synchronize JTAG activation using TCK).
         *
-        * NB! Some targets have JTAG circuitry disabled until a
-        * trst & srst has been asserted.
+        * But some chips only activate JTAG as part of an SRST cycle; SRST
+        * got mixed in.  So it became a hard reset routine, which got used
+        * in more places, and which coped with JTAG reset being forced as
+        * part of SRST (srst_pulls_trst).
         *
-        * NB! here we assume nsrst/ntrst delay are sufficient!
+        * And even more corner cases started to surface:  TRST and/or SRST
+        * assertion timings matter; some chips need other JTAG operations;
+        * TRST/SRST sequences can need to be different from these, etc.
         *
-        * NB! order matters!!!! srst *can* disconnect JTAG circuitry
+        * Systems should override that wrapper to support system-specific
+        * requirements that this not-fully-generic code doesn't handle.
         *
+        * REVISIT once Tcl code can read the reset_config modes, this won't
+        * need to be a C routine at all...
         */
        jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
        if (jtag_reset_config & RESET_HAS_SRST)
@@ -1278,13 +1512,19 @@ int jtag_init_reset(struct command_context_s *cmd_ctx)
 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)
@@ -1329,13 +1569,6 @@ static int jtag_set_speed(int speed)
        return jtag ? jtag->speed(speed) : ERROR_OK;
 }
 
-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");
@@ -1446,3 +1679,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;
+}