reduce arm11 output noise
[fw/openocd] / src / jtag / core.c
index 4e6e5b59fec612ea6ae44dc218e80395765d30f4..8cb4da558edaef6a876ae78d0a7e7351b9803a8b 100644 (file)
@@ -60,11 +60,15 @@ static int jtag_error = ERROR_OK;
 
 static const char *jtag_event_strings[] =
 {
-       [JTAG_TRST_ASSERTED] = "JTAG controller reset (RESET or TRST)",
+       [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;
 
@@ -101,8 +105,9 @@ static jtag_event_callback_t *jtag_event_callbacks;
 
 /* speed in kHz*/
 static int speed_khz = 0;
-/* flag if the kHz speed was defined */
-static 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;
 
 static struct jtag_interface_s *jtag = NULL;
@@ -580,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);
+               }
        }
 }
 
@@ -810,6 +818,7 @@ static int jtag_reset_callback(enum jtag_event event, void *priv)
        {
                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;
        }
@@ -930,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",
@@ -969,11 +978,13 @@ int jtag_examine_chain(void)
        for (unsigned bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
        {
                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;
                }
@@ -1065,7 +1076,8 @@ int jtag_validate_chain(void)
                }
 
                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);
@@ -1140,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;
 }
 
@@ -1205,11 +1234,11 @@ 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 / 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.
@@ -1222,7 +1251,7 @@ 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);
@@ -1255,20 +1284,15 @@ int jtag_init(struct command_context_s *cmd_ctx)
        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;
 }
-int jtag_config_khz(unsigned khz)
-{
-       LOG_DEBUG("handle jtag khz");
-       jtag_set_speed_khz(khz);
 
-       int cur_speed = 0;
+static int jtag_khz_to_speed(unsigned khz, int* speed)
+{
+       LOG_DEBUG("convert khz to interface specific speed value");
+       speed_khz = khz;
        if (jtag != NULL)
        {
                LOG_DEBUG("have interface set up");
@@ -1276,33 +1300,84 @@ int jtag_config_khz(unsigned khz)
                int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
                if (ERROR_OK != retval)
                {
-                       jtag_set_speed_khz(0);
                        return retval;
                }
-               cur_speed = speed_div1;
+               *speed = speed_div1;
        }
-       return jtag_set_speed(cur_speed);
+       return ERROR_OK;
 }
 
-int jtag_get_speed(void)
+static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int* speed)
 {
-       return jtag_speed;
+       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_set_speed(int speed)
+static int jtag_set_speed(int speed)
 {
        jtag_speed = speed;
        /* this command can be called during CONFIG,
         * in which case jtag isn't initialized */
-       hasKHz = !jtag;
        return jtag ? jtag->speed(speed) : ERROR_OK;
 }
 
-int jtag_get_speed_readable(int *speed)
+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");
+       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);
+}
+
+int jtag_config_rclk(unsigned fallback_speed_khz)
 {
-       return jtag ? jtag->speed_div(jtag_get_speed(), speed) : ERROR_OK;
+       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);
 }
 
+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_get_speed_readable(int *khz)
+{
+       return jtag ? jtag->speed_div(jtag_get_speed(), khz) : ERROR_OK;
+}
 
 void jtag_set_verify(bool enable)
 {