reduce arm11 output noise
[openocd.git] / 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)
 {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)