jtag: flush jtag queue after jtag_add_tlr()
[openocd.git] / src / jtag / core.c
index e57f62db7df1012979e05e51d06b318adaf0096b..1d59712d17fa099d9b82770f7185ebc431d13140 100644 (file)
@@ -126,10 +126,10 @@ static int rclk_fallback_speed_khz;
 static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
 static int jtag_speed;
 
-static struct jtag_interface *jtag;
+/* FIXME: change name to this variable, it is not anymore JTAG only */
+static struct adapter_driver *jtag;
 
-/* configuration */
-struct jtag_interface *jtag_interface;
+extern struct adapter_driver *adapter_driver;
 
 void jtag_set_flush_queue_sleep(int ms)
 {
@@ -503,7 +503,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state)
 {
        int retval;
 
-       if (!(jtag->supported & DEBUG_CAP_TMS_SEQ))
+       if (!(jtag->jtag_ops->supported & DEBUG_CAP_TMS_SEQ))
                return ERROR_JTAG_NOT_IMPLEMENTED;
 
        jtag_checks();
@@ -611,22 +611,91 @@ void jtag_add_clocks(int num_cycles)
        }
 }
 
-void swd_add_reset(int req_srst)
+static int adapter_system_reset(int req_srst)
 {
+       int retval;
+
        if (req_srst) {
                if (!(jtag_reset_config & RESET_HAS_SRST)) {
                        LOG_ERROR("BUG: can't assert SRST");
-                       jtag_set_error(ERROR_FAIL);
-                       return;
+                       return ERROR_FAIL;
                }
                req_srst = 1;
        }
 
        /* Maybe change SRST signal state */
        if (jtag_srst != req_srst) {
+               retval = jtag->reset(0, req_srst);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("SRST error");
+                       return ERROR_FAIL;
+               }
+               jtag_srst = req_srst;
+
+               if (req_srst) {
+                       LOG_DEBUG("SRST line asserted");
+                       if (adapter_nsrst_assert_width)
+                               jtag_sleep(adapter_nsrst_assert_width * 1000);
+               } else {
+                       LOG_DEBUG("SRST line released");
+                       if (adapter_nsrst_delay)
+                               jtag_sleep(adapter_nsrst_delay * 1000);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static void legacy_jtag_add_reset(int req_tlr_or_trst, int req_srst)
+{
+       int trst_with_tlr = 0;
+       int new_srst = 0;
+       int new_trst = 0;
+
+       /* 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 (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;
+       }
+
+       /* 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;
+       }
+
+       /* Maybe change TRST and/or SRST signal state */
+       if (jtag_srst != new_srst || jtag_trst != new_trst) {
                int retval;
 
-               retval = interface_jtag_add_reset(0, req_srst);
+               retval = interface_jtag_add_reset(new_trst, new_srst);
                if (retval != ERROR_OK)
                        jtag_set_error(retval);
                else
@@ -636,9 +705,11 @@ void swd_add_reset(int req_srst)
                        LOG_ERROR("TRST/SRST error");
                        return;
                }
+       }
 
-               /* SRST resets everything hooked up to that signal */
-               jtag_srst = req_srst;
+       /* 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");
                        if (adapter_nsrst_assert_width)
@@ -648,21 +719,54 @@ void swd_add_reset(int req_srst)
                        if (adapter_nsrst_delay)
                                jtag_add_sleep(adapter_nsrst_delay * 1000);
                }
+       }
 
-               retval = jtag_execute_queue();
-               if (retval != ERROR_OK) {
-                       LOG_ERROR("SRST timings error");
-                       return;
+       /* 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_add_tlr();
+
+       } else if (jtag_trst != new_trst) {
+               jtag_trst = new_trst;
+               if (jtag_trst) {
+                       LOG_DEBUG("TRST line asserted");
+                       tap_set_state(TAP_RESET);
+                       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);
                }
        }
 }
 
+/* FIXME: name is misleading; we do not plan to "add" reset into jtag queue */
 void jtag_add_reset(int req_tlr_or_trst, int req_srst)
 {
+       int retval;
        int trst_with_tlr = 0;
        int new_srst = 0;
        int new_trst = 0;
 
+       if (!jtag->reset) {
+               legacy_jtag_add_reset(req_tlr_or_trst, req_srst);
+               return;
+       }
+
        /* Without SRST, we must use target-specific JTAG operations
         * on each target; callers should not be requesting SRST when
         * that signal doesn't exist.
@@ -704,15 +808,12 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
 
        /* Maybe change TRST and/or SRST signal state */
        if (jtag_srst != new_srst || jtag_trst != new_trst) {
-               int retval;
-
-               retval = interface_jtag_add_reset(new_trst, new_srst);
-               if (retval != ERROR_OK)
-                       jtag_set_error(retval);
-               else
-                       retval = jtag_execute_queue();
+               /* guarantee jtag queue empty before changing reset status */
+               jtag_execute_queue();
 
+               retval = jtag->reset(new_trst, new_srst);
                if (retval != ERROR_OK) {
+                       jtag_set_error(retval);
                        LOG_ERROR("TRST/SRST error");
                        return;
                }
@@ -741,6 +842,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
        if (trst_with_tlr) {
                LOG_DEBUG("JTAG reset with TLR instead of TRST");
                jtag_add_tlr();
+               jtag_execute_queue();
 
        } else if (jtag_trst != new_trst) {
                jtag_trst = new_trst;
@@ -836,7 +938,88 @@ int default_interface_jtag_execute_queue(void)
                return ERROR_FAIL;
        }
 
-       return jtag->execute_queue();
+       if (!transport_is_jtag()) {
+               /*
+                * FIXME: This should not happen!
+                * There could be old code that queues jtag commands with non jtag interfaces so, for
+                * the moment simply highlight it by log an error and return on empty execute_queue.
+                * We should fix it quitting with assert(0) because it is an internal error.
+                * The fix can be applied immediately after next release (v0.11.0 ?)
+                */
+               LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface");
+               if (!jtag->jtag_ops || !jtag->jtag_ops->execute_queue)
+                       return ERROR_OK;
+       }
+
+       int result = jtag->jtag_ops->execute_queue();
+
+#if !BUILD_ZY1000
+       /* Only build this if we use a regular driver with a command queue.
+        * Otherwise jtag_command_queue won't be found at compile/link time. Its
+        * definition is in jtag/commands.c, which is only built/linked by
+        * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables
+        * aren't accessible here. */
+       struct jtag_command *cmd = jtag_command_queue;
+       while (debug_level >= LOG_LVL_DEBUG && cmd) {
+               switch (cmd->type) {
+                       case JTAG_SCAN:
+                               LOG_DEBUG_IO("JTAG %s SCAN to %s",
+                                               cmd->cmd.scan->ir_scan ? "IR" : "DR",
+                                               tap_state_name(cmd->cmd.scan->end_state));
+                               for (int i = 0; i < cmd->cmd.scan->num_fields; i++) {
+                                       struct scan_field *field = cmd->cmd.scan->fields + i;
+                                       if (field->out_value) {
+                                               char *str = buf_to_str(field->out_value, field->num_bits, 16);
+                                               LOG_DEBUG_IO("  %db out: %s", field->num_bits, str);
+                                               free(str);
+                                       }
+                                       if (field->in_value) {
+                                               char *str = buf_to_str(field->in_value, field->num_bits, 16);
+                                               LOG_DEBUG_IO("  %db  in: %s", field->num_bits, str);
+                                               free(str);
+                                       }
+                               }
+                               break;
+                       case JTAG_TLR_RESET:
+                               LOG_DEBUG_IO("JTAG TLR RESET to %s",
+                                               tap_state_name(cmd->cmd.statemove->end_state));
+                               break;
+                       case JTAG_RUNTEST:
+                               LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s",
+                                               cmd->cmd.runtest->num_cycles,
+                                               tap_state_name(cmd->cmd.runtest->end_state));
+                               break;
+                       case JTAG_RESET:
+                               {
+                                       const char *reset_str[3] = {
+                                               "leave", "deassert", "assert"
+                                       };
+                                       LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST",
+                                                       reset_str[cmd->cmd.reset->trst + 1],
+                                                       reset_str[cmd->cmd.reset->srst + 1]);
+                               }
+                               break;
+                       case JTAG_PATHMOVE:
+                               LOG_DEBUG_IO("JTAG PATHMOVE (TODO)");
+                               break;
+                       case JTAG_SLEEP:
+                               LOG_DEBUG_IO("JTAG SLEEP (TODO)");
+                               break;
+                       case JTAG_STABLECLOCKS:
+                               LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)");
+                               break;
+                       case JTAG_TMS:
+                               LOG_DEBUG_IO("JTAG TMS (TODO)");
+                               break;
+                       default:
+                               LOG_ERROR("Unknown JTAG command: %d", cmd->type);
+                               break;
+               }
+               cmd = cmd->next;
+       }
+#endif
+
+       return result;
 }
 
 void jtag_execute_queue_noclear(void)
@@ -1107,7 +1290,8 @@ static int jtag_examine_chain(void)
 
                if ((idcode & 1) == 0) {
                        /* Zero for LSB indicates a device in bypass */
-                       LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name);
+                       LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%x)",
+                                       tap->dotted_name, idcode);
                        tap->hasidcode = false;
                        tap->idcode = 0;
 
@@ -1335,31 +1519,18 @@ int adapter_init(struct command_context *cmd_ctx)
        if (jtag)
                return ERROR_OK;
 
-       if (!jtag_interface) {
-               /* nothing was previously specified by "interface" command */
+       if (!adapter_driver) {
+               /* nothing was previously specified by "adapter driver" command */
                LOG_ERROR("Debug Adapter has to be specified, "
-                       "see \"interface\" command");
+                       "see \"adapter driver\" command");
                return ERROR_JTAG_INVALID_INTERFACE;
        }
 
        int retval;
-       retval = jtag_interface->init();
+       retval = adapter_driver->init();
        if (retval != ERROR_OK)
                return retval;
-       jtag = jtag_interface;
-
-       /* LEGACY SUPPORT ... adapter drivers  must declare what
-        * transports they allow.  Until they all do so, assume
-        * the legacy drivers are JTAG-only
-        */
-       if (!transports_are_declared()) {
-               LOG_ERROR("Adapter driver '%s' did not declare "
-                       "which transports it allows; assuming "
-                       "JTAG-only", jtag->name);
-               retval = allow_transports(cmd_ctx, jtag_only);
-               if (retval != ERROR_OK)
-                       return retval;
-       }
+       jtag = adapter_driver;
 
        if (jtag->speed == NULL) {
                LOG_INFO("This adapter doesn't support configurable speed");
@@ -1368,7 +1539,7 @@ int adapter_init(struct command_context *cmd_ctx)
 
        if (CLOCK_MODE_UNSELECTED == clock_mode) {
                LOG_ERROR("An adapter speed is not selected in the init script."
-                       " Insert a call to adapter_khz or jtag_rclk to proceed.");
+                       " Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed.");
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -1499,17 +1670,19 @@ int adapter_quit(void)
 
 int swd_init_reset(struct command_context *cmd_ctx)
 {
-       int retval = adapter_init(cmd_ctx);
+       int retval, retval1;
+
+       retval = adapter_init(cmd_ctx);
        if (retval != ERROR_OK)
                return retval;
 
        LOG_DEBUG("Initializing with hard SRST reset");
 
        if (jtag_reset_config & RESET_HAS_SRST)
-               swd_add_reset(1);
-       swd_add_reset(0);
-       retval = jtag_execute_queue();
-       return retval;
+               retval = adapter_system_reset(1);
+       retval1 = adapter_system_reset(0);
+
+       return (retval == ERROR_OK) ? retval1 : retval;
 }
 
 int jtag_init_reset(struct command_context *cmd_ctx)
@@ -1611,14 +1784,18 @@ static int adapter_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");
-               int speed_div1;
-               int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
-               if (ERROR_OK != retval)
-                       return retval;
-               *speed = speed_div1;
+       if (!jtag)
+               return ERROR_OK;
+       LOG_DEBUG("have interface set up");
+       if (!jtag->khz) {
+               LOG_ERROR("Translation from khz to jtag_speed not implemented");
+               return ERROR_FAIL;
        }
+       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;
 }
 
@@ -1681,7 +1858,13 @@ int jtag_get_speed_readable(int *khz)
        int retval = jtag_get_speed(&jtag_speed_var);
        if (retval != ERROR_OK)
                return retval;
-       return jtag ? jtag->speed_div(jtag_speed_var, khz) : ERROR_OK;
+       if (!jtag)
+               return ERROR_OK;
+       if (!jtag->speed_div) {
+               LOG_ERROR("Translation from jtag_speed to khz not implemented");
+               return ERROR_FAIL;
+       }
+       return jtag->speed_div(jtag_speed_var, khz);
 }
 
 void jtag_set_verify(bool enable)
@@ -1712,12 +1895,20 @@ int jtag_power_dropout(int *dropout)
                LOG_ERROR("No Valid JTAG Interface Configured.");
                exit(-1);
        }
-       return jtag->power_dropout(dropout);
+       if (jtag->power_dropout)
+               return jtag->power_dropout(dropout);
+
+       *dropout = 0; /* by default we can't detect power dropout */
+       return ERROR_OK;
 }
 
 int jtag_srst_asserted(int *srst_asserted)
 {
-       return jtag->srst_asserted(srst_asserted);
+       if (jtag->srst_asserted)
+               return jtag->srst_asserted(srst_asserted);
+
+       *srst_asserted = 0; /* by default we can't detect srst asserted */
+       return ERROR_OK;
 }
 
 enum reset_types jtag_get_reset_config(void)
@@ -1814,42 +2005,89 @@ bool transport_is_jtag(void)
        return get_current_transport() == &jtag_transport;
 }
 
-void adapter_assert_reset(void)
+int adapter_resets(int trst, int srst)
+{
+       if (get_current_transport() == NULL) {
+               LOG_ERROR("transport is not selected");
+               return ERROR_FAIL;
+       }
+
+       if (transport_is_jtag()) {
+               if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+                       LOG_ERROR("adapter has no srst signal");
+                       return ERROR_FAIL;
+               }
+
+               /* adapters without trst signal will eventually use tlr sequence */
+               jtag_add_reset(trst, srst);
+               return ERROR_OK;
+       } else if (transport_is_swd() || transport_is_hla()) {
+               if (trst == TRST_ASSERT) {
+                       LOG_ERROR("transport %s has no trst signal",
+                               get_current_transport()->name);
+                       return ERROR_FAIL;
+               }
+
+               if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+                       LOG_ERROR("adapter has no srst signal");
+                       return ERROR_FAIL;
+               }
+               adapter_system_reset(srst);
+               return ERROR_OK;
+       }
+
+       if (trst == TRST_DEASSERT && srst == SRST_DEASSERT)
+               return ERROR_OK;
+
+       LOG_ERROR("reset is not supported on transport %s",
+               get_current_transport()->name);
+
+       return ERROR_FAIL;
+}
+
+int adapter_assert_reset(void)
 {
        if (transport_is_jtag()) {
                if (jtag_reset_config & RESET_SRST_PULLS_TRST)
                        jtag_add_reset(1, 1);
                else
                        jtag_add_reset(0, 1);
-       } else if (transport_is_swd())
-               swd_add_reset(1);
+               return ERROR_OK;
+       } else if (transport_is_swd() || transport_is_hla() ||
+                          transport_is_dapdirect_jtag() || transport_is_dapdirect_swd())
+               return adapter_system_reset(1);
        else if (get_current_transport() != NULL)
                LOG_ERROR("reset is not supported on %s",
                        get_current_transport()->name);
        else
                LOG_ERROR("transport is not selected");
+       return ERROR_FAIL;
 }
 
-void adapter_deassert_reset(void)
+int adapter_deassert_reset(void)
 {
-       if (transport_is_jtag())
+       if (transport_is_jtag()) {
                jtag_add_reset(0, 0);
-       else if (transport_is_swd())
-               swd_add_reset(0);
+               return ERROR_OK;
+       } else if (transport_is_swd() || transport_is_hla() ||
+                        transport_is_dapdirect_jtag() || transport_is_dapdirect_swd())
+               return adapter_system_reset(0);
        else if (get_current_transport() != NULL)
                LOG_ERROR("reset is not supported on %s",
                        get_current_transport()->name);
        else
                LOG_ERROR("transport is not selected");
+       return ERROR_FAIL;
 }
 
 int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
-                        uint32_t port_size, unsigned int *trace_freq)
+               uint32_t port_size, unsigned int *trace_freq,
+               unsigned int traceclkin_freq, uint16_t *prescaler)
 {
-       if (jtag->config_trace)
-               return jtag->config_trace(enabled, pin_protocol, port_size,
-                                         trace_freq);
-       else if (enabled) {
+       if (jtag->config_trace) {
+               return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq,
+                       traceclkin_freq, prescaler);
+       else if (enabled) {
                LOG_ERROR("The selected interface does not support tracing");
                return ERROR_FAIL;
        }

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)