reduce arm11 output noise
[fw/openocd] / src / jtag / core.c
index 45ece3c4cf017891f191ad157d871d57fe488848..8cb4da558edaef6a876ae78d0a7e7351b9803a8b 100644 (file)
@@ -2,7 +2,7 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
- *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
+ *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2009 SoftPLC Corporation                                *
@@ -46,23 +46,29 @@ 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);
 
-/* note that this is not marked as static as it must be available from outside core.c for those
-   that implement the jtag_xxx() minidriver layer
-*/
-int jtag_error=ERROR_OK;
+/**
+ * The jtag_error variable is set when an error occurs while executing
+ * the queue.  Application code may set this using jtag_set_error(),
+ * when an error occurs during processing that should be reported during
+ * jtag_execute_queue().
+ *
+ * Tts value may be checked with jtag_get_error() and cleared with
+ * jtag_error_clear().  This value is returned (and cleared) by
+ * jtag_execute_queue().
+ */
+static int jtag_error = ERROR_OK;
 
-char* jtag_event_strings[] =
+static const char *jtag_event_strings[] =
 {
-       "JTAG controller reset (RESET or TRST)"
-};
-
-const Jim_Nvp nvp_jtag_tap_event[] = {
-       { .value = JTAG_TAP_EVENT_ENABLE,       .name = "tap-enable" },
-       { .value = JTAG_TAP_EVENT_DISABLE,      .name = "tap-disable" },
-
-       { .name = NULL, .value = -1 }
+       [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;
 
@@ -76,30 +82,56 @@ static jtag_tap_t *__jtag_all_taps = NULL;
  */
 static unsigned jtag_num_taps = 0;
 
-enum reset_types jtag_reset_config = RESET_NONE;
-tap_state_t cmd_queue_end_state = TAP_RESET;
+static enum reset_types jtag_reset_config = RESET_NONE;
+static tap_state_t cmd_queue_end_state = TAP_RESET;
 tap_state_t cmd_queue_cur_state = TAP_RESET;
 
-int jtag_verify_capture_ir = 1;
-int jtag_verify = 1;
+static bool jtag_verify_capture_ir = true;
+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 */
 
+typedef struct jtag_event_callback_s
+{
+       jtag_event_handler_t          callback;
+       void*                         priv;
+       struct jtag_event_callback_s* next;
+} jtag_event_callback_t;
+
 /* callbacks to inform high-level handlers about JTAG state changes */
-jtag_event_callback_t *jtag_event_callbacks;
+static jtag_event_callback_t *jtag_event_callbacks;
 
 /* speed in kHz*/
 static int speed_khz = 0;
-/* flag if the kHz speed was defined */
-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;
 
-struct jtag_interface_s *jtag = NULL;
+static struct jtag_interface_s *jtag = NULL;
 
 /* configuration */
 jtag_interface_t *jtag_interface = NULL;
-int jtag_speed = 0;
+
+void jtag_set_error(int error)
+{
+       if ((error == ERROR_OK) || (jtag_error != ERROR_OK))
+               return;
+       jtag_error = error;
+}
+int jtag_get_error(void)
+{
+       return jtag_error;
+}
+int jtag_error_clear(void)
+{
+       int temp = jtag_error;
+       jtag_error = ERROR_OK;
+       return temp;
+}
+
 
 jtag_tap_t *jtag_all_taps(void)
 {
@@ -115,7 +147,7 @@ unsigned jtag_tap_count_enabled(void)
 {
        jtag_tap_t *t = jtag_all_taps();
        unsigned n = 0;
-       while(t)
+       while (t)
        {
                if (t->enabled)
                        n++;
@@ -130,15 +162,27 @@ void jtag_tap_add(struct jtag_tap_s *t)
        t->abs_chain_position = jtag_num_taps++;
 
        jtag_tap_t **tap = &__jtag_all_taps;
-       while(*tap != NULL)
+       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)
+{
+       jtag_tap_t *t = jtag_all_taps();
+
+       while (t && n-- > 0)
+               t = t->next_tap;
+
+       return t;
+}
+
 jtag_tap_t *jtag_tap_by_string(const char *s)
 {
        /* try by name first */
        jtag_tap_t *t = jtag_all_taps();
+
        while (t)
        {
                if (0 == strcmp(t->dotted_name, s))
@@ -147,12 +191,20 @@ jtag_tap_t *jtag_tap_by_string(const char *s)
        }
 
        /* no tap found by name, so try to parse the name as a number */
-       char *cp;
-       unsigned n = strtoul(s, &cp, 0);
-       if ((s == cp) || (*cp != 0))
+       unsigned n;
+       if (parse_uint(s, &n) != ERROR_OK)
                return NULL;
 
-       return jtag_tap_by_position(n);
+       /* FIXME remove this numeric fallback code late June 2010, along
+        * with all info in the User's Guide that TAPs have numeric IDs.
+        * Also update "scan_chain" output to not display the numbers.
+        */
+       t = jtag_tap_by_position(n);
+       if (t)
+               LOG_WARNING("Specify TAP '%s' by name, not number %u",
+                       t->dotted_name, n);
+
+       return t;
 }
 
 jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
@@ -166,15 +218,16 @@ jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
        return t;
 }
 
-/* returns a pointer to the n-th device in the scan chain */
-jtag_tap_t *jtag_tap_by_position(unsigned n)
+jtag_tap_t* jtag_tap_next_enabled(jtag_tap_t* p)
 {
-       jtag_tap_t *t = jtag_all_taps();
-
-       while (t && n-- > 0)
-               t = t->next_tap;
-
-       return t;
+       p = p ? p->next_tap : jtag_all_taps();
+       while (p)
+       {
+               if (p->enabled)
+                       return p;
+               p = p->next_tap;
+       }
+       return NULL;
 }
 
 const char *jtag_tap_name(const jtag_tap_t *tap)
@@ -183,7 +236,7 @@ const char *jtag_tap_name(const jtag_tap_t *tap)
 }
 
 
-int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv)
+int jtag_register_event_callback(jtag_event_handler_t callback, void *priv)
 {
        jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
 
@@ -207,24 +260,30 @@ int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *pr
        return ERROR_OK;
 }
 
-int jtag_unregister_event_callback(int (*callback)(enum jtag_event event, void *priv))
+int jtag_unregister_event_callback(jtag_event_handler_t callback, void *priv)
 {
-       jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
+       jtag_event_callback_t **callbacks_p;
+       jtag_event_callback_t **next;
 
        if (callback == NULL)
        {
                return ERROR_INVALID_ARGUMENTS;
        }
 
-       while (*callbacks_p)
+       for (callbacks_p = &jtag_event_callbacks;
+                       *callbacks_p != NULL;
+                       callbacks_p = next)
        {
-               jtag_event_callback_t **next = &((*callbacks_p)->next);
+               next = &((*callbacks_p)->next);
+
+               if ((*callbacks_p)->priv != priv)
+                       continue;
+
                if ((*callbacks_p)->callback == callback)
                {
                        free(*callbacks_p);
                        *callbacks_p = *next;
                }
-               callbacks_p = next;
        }
 
        return ERROR_OK;
@@ -238,8 +297,12 @@ int jtag_call_event_callbacks(enum jtag_event event)
 
        while (callback)
        {
+               jtag_event_callback_t *next;
+
+               /* callback may remove itself */
+               next = callback->next;
                callback->callback(event, callback->priv);
-               callback = callback->next;
+               callback = next;
        }
 
        return ERROR_OK;
@@ -254,7 +317,7 @@ static void jtag_prelude(tap_state_t state)
 {
        jtag_checks();
 
-       assert(state!=TAP_INVALID);
+       assert(state != TAP_INVALID);
 
        cmd_queue_cur_state = state;
 }
@@ -276,7 +339,7 @@ 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)
 {
-       if (jtag_verify&&jtag_verify_capture_ir)
+       if (jtag_verify && jtag_verify_capture_ir)
        {
                /* 8 x 32 bit id's is enough for all invocations */
 
@@ -285,8 +348,8 @@ void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t st
                        /* if we are to run a verification of the ir scan, we need to get the input back.
                         * We may have to allocate space if the caller didn't ask for the input back.
                         */
-                       in_fields[j].check_value=in_fields[j].tap->expected;
-                       in_fields[j].check_mask=in_fields[j].tap->expected_mask;
+                       in_fields[j].check_value = in_fields[j].tap->expected;
+                       in_fields[j].check_mask = in_fields[j].tap->expected_mask;
                }
                jtag_add_scan_check(jtag_add_ir_scan_noverify, in_num_fields, in_fields, state);
        } else
@@ -305,23 +368,23 @@ void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields,
        jtag_set_error(retval);
 }
 
-void jtag_add_callback(jtag_callback1_t f, u8 *in)
+void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0)
 {
-       interface_jtag_add_callback(f, in);
+       interface_jtag_add_callback(f, data0);
 }
 
-void jtag_add_callback4(jtag_callback_t f, u8 *in,
+void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0,
                jtag_callback_data_t data1, jtag_callback_data_t data2,
                jtag_callback_data_t data3)
 {
-       interface_jtag_add_callback4(f, in, data1, data2, data3);
+       interface_jtag_add_callback4(f, data0, data1, data2, data3);
 }
 
-int jtag_check_value_inner(u8 *captured, u8 *in_check_value, u8 *in_check_mask, int num_bits);
+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(u8 *in, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
+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(in, (u8 *)data1, (u8 *)data2, (int)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),
@@ -345,7 +408,7 @@ static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const s
                if ((in_fields[i].check_value != NULL) && (in_fields[i].in_value != NULL))
                {
                        /* this is synchronous for a minidriver */
-                       jtag_add_callback4(jtag_check_value_mask_callback, in_fields[i].in_value,
+                       jtag_add_callback4(jtag_check_value_mask_callback, (jtag_callback_data_t)in_fields[i].in_value,
                                (jtag_callback_data_t)in_fields[i].check_value,
                                (jtag_callback_data_t)in_fields[i].check_mask,
                                (jtag_callback_data_t)in_fields[i].num_bits);
@@ -394,7 +457,7 @@ void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields,
 }
 
 void jtag_add_dr_out(jtag_tap_t* tap,
-               int num_fields, const int* num_bits, const u32* value,
+               int num_fields, const int* num_bits, const uint32_t* value,
                tap_state_t end_state)
 {
        assert(end_state != TAP_INVALID);
@@ -434,7 +497,7 @@ void jtag_add_pathmove(int num_states, const tap_state_t *path)
                        return;
                }
 
-               if ( tap_state_transition(cur_state, true)  != path[i]
+               if (tap_state_transition(cur_state, true)  != path[i]
                  && tap_state_transition(cur_state, false) != path[i])
                {
                        LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
@@ -451,6 +514,50 @@ void jtag_add_pathmove(int num_states, const tap_state_t *path)
        cmd_queue_cur_state = path[num_states - 1];
 }
 
+int jtag_add_statemove(tap_state_t goal_state)
+{
+       tap_state_t cur_state = cmd_queue_cur_state;
+
+       LOG_DEBUG("cur_state=%s goal_state=%s",
+               tap_state_name(cur_state),
+               tap_state_name(goal_state));
+
+
+       if (goal_state == cur_state)
+               ;       /* nothing to do */
+       else if (goal_state == TAP_RESET)
+       {
+               jtag_add_tlr();
+       }
+       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);
+               unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state);
+               tap_state_t moves[8];
+               assert(tms_count < DIM(moves));
+
+               for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1)
+               {
+                       bool bit = tms_bits & 1;
+
+                       cur_state = tap_state_transition(cur_state, bit);
+                       moves[i] = cur_state;
+               }
+
+               jtag_add_pathmove(tms_count, moves);
+       }
+       else if (tap_state_transition(cur_state, true)  == goal_state
+               ||   tap_state_transition(cur_state, false) == goal_state)
+       {
+               jtag_add_pathmove(1, &goal_state);
+       }
+
+       else
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
 void jtag_add_runtest(int num_cycles, tap_state_t state)
 {
        jtag_prelude(state);
@@ -478,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);
+               }
        }
 }
 
@@ -584,7 +694,7 @@ tap_state_t jtag_set_end_state(tap_state_t state)
                LOG_ERROR("BUG: TAP_DRSHIFT/IRSHIFT can't be end state. Calling code should use a larger scan field");
        }
 
-       if (state!=TAP_INVALID)
+       if (state != TAP_INVALID)
                cmd_queue_end_state = state;
        return cmd_queue_end_state;
 }
@@ -594,14 +704,14 @@ tap_state_t jtag_get_end_state(void)
        return cmd_queue_end_state;
 }
 
-void jtag_add_sleep(u32 us)
+void jtag_add_sleep(uint32_t us)
 {
        /// @todo Here, keep_alive() appears to be a layering violation!!!
        keep_alive();
        jtag_set_error(interface_jtag_add_sleep(us));
 }
 
-int jtag_check_value_inner(u8 *captured, u8 *in_check_value, u8 *in_check_mask, int num_bits)
+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;
 
@@ -612,7 +722,7 @@ int jtag_check_value_inner(u8 *captured, u8 *in_check_value, u8 *in_check_mask,
        else
                compare_failed = buf_cmp(captured, in_check_value, num_bits);
 
-       if (compare_failed){
+       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
@@ -650,11 +760,11 @@ int jtag_check_value_inner(u8 *captured, u8 *in_check_value, u8 *in_check_mask,
        return retval;
 }
 
-void jtag_check_value_mask(scan_field_t *field, u8 *value, u8 *mask)
+void jtag_check_value_mask(scan_field_t *field, uint8_t *value, uint8_t *mask)
 {
        assert(field->in_value != NULL);
 
-       if (value==NULL)
+       if (value == NULL)
        {
                /* no checking to do */
                return;
@@ -662,7 +772,7 @@ void jtag_check_value_mask(scan_field_t *field, u8 *value, u8 *mask)
 
        jtag_execute_queue_noclear();
 
-       int retval=jtag_check_value_inner(field->in_value, value, mask, field->num_bits);
+       int retval = jtag_check_value_inner(field->in_value, value, mask, field->num_bits);
        jtag_set_error(retval);
 }
 
@@ -706,6 +816,9 @@ static int jtag_reset_callback(enum jtag_event event, void *priv)
 
        if (event == JTAG_TRST_ASSERTED)
        {
+               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;
        }
@@ -713,7 +826,7 @@ static int jtag_reset_callback(enum jtag_event event, void *priv)
        return ERROR_OK;
 }
 
-void jtag_sleep(u32 us)
+void jtag_sleep(uint32_t us)
 {
        alive_sleep(us/1000);
 }
@@ -725,7 +838,7 @@ void jtag_sleep(u32 us)
 #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
 #define EXTRACT_VER(X)  (((X) & 0xf0000000) >> 28)
 
-static int jtag_examine_chain_execute(u8 *idcode_buffer, unsigned num_idcode)
+static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
 {
        scan_field_t field = {
                        .tap = NULL,
@@ -742,10 +855,10 @@ static int jtag_examine_chain_execute(u8 *idcode_buffer, unsigned num_idcode)
        return jtag_execute_queue();
 }
 
-static bool jtag_examine_chain_check(u8 *idcodes, unsigned count)
+static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count)
 {
-       u8 zero_check = 0x0;
-       u8 one_check = 0xff;
+       uint8_t zero_check = 0x0;
+       uint8_t one_check = 0xff;
 
        for (unsigned i = 0; i < count * 4; i++)
        {
@@ -765,16 +878,19 @@ static bool jtag_examine_chain_check(u8 *idcodes, unsigned count)
 }
 
 static void jtag_examine_chain_display(enum log_levels level, const char *msg,
-               const char *name, u32 idcode)
+               const char *name, uint32_t idcode)
 {
        log_printf_lf(level, __FILE__, __LINE__, __FUNCTION__,
-                       "JTAG tap: %s %16.16s: 0x%08x "
-                       "(mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)",
-               name, msg, idcode,
-               EXTRACT_MFG(idcode), EXTRACT_PART(idcode), EXTRACT_VER(idcode) );
+                                 "JTAG tap: %s %16.16s: 0x%08x "
+                                 "(mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)",
+                                 name, msg,
+                                 (unsigned int)idcode,
+                                 (unsigned int)EXTRACT_MFG(idcode),
+                                 (unsigned int)EXTRACT_PART(idcode),
+                                 (unsigned int)EXTRACT_VER(idcode));
 }
 
-static bool jtag_idcode_is_final(u32 idcode)
+static bool jtag_idcode_is_final(uint32_t idcode)
 {
                return idcode == 0x000000FF || idcode == 0xFFFFFFFF;
 }
@@ -785,17 +901,17 @@ static bool jtag_idcode_is_final(u32 idcode)
  * read back correctly.  This can help identify and diagnose problems
  * with the JTAG chain earlier, gives more helpful/explicit error messages.
  */
-static void jtag_examine_chain_end(u8 *idcodes, unsigned count, unsigned max)
+static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max)
 {
        bool triggered = false;
-       for ( ; count < max - 31; count += 32)
+       for (; count < max - 31; count += 32)
        {
-               u32 idcode = buf_get_u32(idcodes, 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))
                        continue;
                LOG_WARNING("Unexpected idcode after end of chain: %d 0x%08x",
-                               count, idcode);
+                                       count, (unsigned int)idcode);
                triggered = true;
        }
 }
@@ -813,7 +929,7 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
        }
 
        /* Loop over the expected identification codes and test for a match */
-       u8 ii;
+       uint8_t ii;
        for (ii = 0; ii < tap->expected_ids_cnt; ii++)
        {
                if (tap->idcode == tap->expected_ids[ii])
@@ -823,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",
@@ -843,7 +959,7 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
  */
 int jtag_examine_chain(void)
 {
-       u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
+       uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
        unsigned device_count = 0;
 
        jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
@@ -861,12 +977,14 @@ int jtag_examine_chain(void)
 
        for (unsigned bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
        {
-               u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32);
+               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;
                }
@@ -921,15 +1039,15 @@ int jtag_validate_chain(void)
 {
        jtag_tap_t *tap;
        int total_ir_length = 0;
-       u8 *ir_test = NULL;
+       uint8_t *ir_test = NULL;
        scan_field_t field;
        int chain_pos = 0;
 
        tap = NULL;
        total_ir_length = 0;
-       for(;;){
+       for (;;) {
                tap = jtag_tap_next_enabled(tap);
-               if( tap == NULL ){
+               if (tap == NULL) {
                        break;
                }
                total_ir_length += tap->ir_length;
@@ -951,14 +1069,15 @@ int jtag_validate_chain(void)
        tap = NULL;
        chain_pos = 0;
        int val;
-       for(;;){
+       for (;;) {
                tap = jtag_tap_next_enabled(tap);
-               if( tap == NULL ){
+               if (tap == NULL) {
                        break;
                }
 
                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);
@@ -993,6 +1112,7 @@ void jtag_tap_init(jtag_tap_t *tap)
        tap->expected_mask = malloc(tap->ir_length);
        tap->cur_instr = malloc(tap->ir_length);
 
+       /// @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);
@@ -1005,13 +1125,15 @@ 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,
-                               tap->ir_capture_value, tap->ir_capture_mask);
+                         (unsigned int)(tap->ir_capture_value), (unsigned int)(tap->ir_capture_mask));
        jtag_tap_add(tap);
 }
 
 void jtag_tap_free(jtag_tap_t *tap)
 {
-       /// @todo is anything missing? no memory leaks please 
+       jtag_unregister_event_callback(&jtag_reset_callback, tap);
+
+       /// @todo is anything missing? no memory leaks please
        free((void *)tap->expected_ids);
        free((void *)tap->chip);
        free((void *)tap->tapname);
@@ -1030,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;
 }
 
@@ -1051,13 +1190,13 @@ static int jtag_init_inner(struct command_context_s *cmd_ctx)
        LOG_DEBUG("Init JTAG chain");
 
        tap = jtag_tap_next_enabled(NULL);
-       if( tap == NULL ){
+       if (tap == NULL) {
                LOG_ERROR("There are no enabled taps?");
                return ERROR_JTAG_INIT_FAILED;
        }
 
        jtag_add_tlr();
-       if ((retval=jtag_execute_queue())!=ERROR_OK)
+       if ((retval = jtag_execute_queue()) != ERROR_OK)
                return retval;
 
        /* examine chain first, as this could discover the real chain layout */
@@ -1092,14 +1231,14 @@ int jtag_init_reset(struct command_context_s *cmd_ctx)
 {
        int retval;
 
-       if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
+       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.
@@ -1112,11 +1251,11 @@ 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);
-               if ((jtag_reset_config & RESET_SRST_PULLS_TRST)==0)
+               if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0)
                        jtag_add_reset(0, 1);
        }
        jtag_add_reset(0, 0);
@@ -1136,118 +1275,147 @@ 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)
+       if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK)
                return retval;
-       if (jtag_init_inner(cmd_ctx)==ERROR_OK)
+       if (jtag_init_inner(cmd_ctx) == ERROR_OK)
        {
                return ERROR_OK;
        }
        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;
 }
 
-void jtag_set_verify(bool enable)
+static int jtag_khz_to_speed(unsigned khz, int* speed)
 {
-       jtag_verify = enable;
+       LOG_DEBUG("convert khz to interface specific speed value");
+       speed_khz = khz;
+       if (jtag != NULL)
+       {
+               LOG_DEBUG("have interface set up");
+               int speed_div1;
+               int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
+               if (ERROR_OK != retval)
+               {
+                       return retval;
+               }
+               *speed = speed_div1;
+       }
+       return ERROR_OK;
 }
 
-bool jtag_will_verify()
+static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int* speed)
 {
-       return jtag_verify;
+       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_power_dropout(int *dropout)
+static int jtag_set_speed(int speed)
 {
-       return jtag->power_dropout(dropout);
+       jtag_speed = speed;
+       /* this command can be called during CONFIG,
+        * in which case jtag isn't initialized */
+       return jtag ? jtag->speed(speed) : ERROR_OK;
 }
 
-int jtag_srst_asserted(int *srst_asserted)
+int jtag_config_speed(int speed)
 {
-       return jtag->srst_asserted(srst_asserted);
+       LOG_DEBUG("handle jtag speed");
+       clock_mode = CLOCK_MODE_SPEED;
+       return jtag_set_speed(speed);
 }
 
-void jtag_tap_handle_event( jtag_tap_t * tap, enum jtag_tap_event e)
+int jtag_config_khz(unsigned khz)
 {
-       jtag_tap_event_action_t * jteap;
-       int done;
-
-       jteap = tap->event_action;
-
-       done = 0;
-       while (jteap) {
-               if (jteap->event == e) {
-                       done = 1;
-                       LOG_DEBUG( "JTAG tap: %s event: %d (%s) action: %s\n",
-                                       tap->dotted_name,
-                                       e,
-                                       Jim_Nvp_value2name_simple(nvp_jtag_tap_event, e)->name,
-                                       Jim_GetString(jteap->body, NULL) );
-                       if (Jim_EvalObj(interp, jteap->body) != JIM_OK) {
-                               Jim_PrintErrorMessage(interp);
-                       }
-               }
+       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);
+}
 
-               jteap = jteap->next;
-       }
+int jtag_config_rclk(unsigned fallback_speed_khz)
+{
+       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);
+}
 
-       if (!done) {
-               LOG_DEBUG( "event %d %s - no action",
-                               e,
-                               Jim_Nvp_value2name_simple( nvp_jtag_tap_event, e)->name);
+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_add_statemove(tap_state_t goal_state)
+int jtag_get_speed_readable(int *khz)
 {
-       tap_state_t cur_state = cmd_queue_cur_state;
-
-       LOG_DEBUG( "cur_state=%s goal_state=%s",
-               tap_state_name(cur_state),
-               tap_state_name(goal_state) );
+       return jtag ? jtag->speed_div(jtag_get_speed(), khz) : ERROR_OK;
+}
 
+void jtag_set_verify(bool enable)
+{
+       jtag_verify = enable;
+}
 
-       if (goal_state==cur_state )
-               ;       /* nothing to do */
-       else if( goal_state==TAP_RESET )
-       {
-               jtag_add_tlr();
-       }
-       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);
-               unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state);
-               tap_state_t moves[8];
-               assert(tms_count < DIM(moves));
+bool jtag_will_verify()
+{
+       return jtag_verify;
+}
 
-               for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1)
-               {
-                       bool bit = tms_bits & 1;
+void jtag_set_verify_capture_ir(bool enable)
+{
+       jtag_verify_capture_ir = enable;
+}
 
-                       cur_state = tap_state_transition(cur_state, bit);
-                       moves[i] = cur_state;
-               }
+bool jtag_will_verify_capture_ir()
+{
+       return jtag_verify_capture_ir;
+}
 
-               jtag_add_pathmove(tms_count, moves);
-       }
-       else if( tap_state_transition(cur_state, true)  == goal_state
-               ||   tap_state_transition(cur_state, false) == goal_state )
-       {
-               jtag_add_pathmove(1, &goal_state);
-       }
+int jtag_power_dropout(int *dropout)
+{
+       return jtag->power_dropout(dropout);
+}
 
-       else
-               return ERROR_FAIL;
+int jtag_srst_asserted(int *srst_asserted)
+{
+       return jtag->srst_asserted(srst_asserted);
+}
 
-       return ERROR_OK;
+enum reset_types jtag_get_reset_config(void)
+{
+       return jtag_reset_config;
+}
+void jtag_set_reset_config(enum reset_types type)
+{
+       jtag_reset_config = type;
 }
 
 int jtag_get_trst(void)