Add a new JTAG "setup" event; use for better DaVinci ICEpick support.
[fw/openocd] / src / jtag / tcl.c
index 759f8f7c4125f33c1b228a06ee528dd6451c2d26..212be35577bc6a8383c3c3a98fe89f3d2fa6cd75 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                                *
@@ -41,6 +41,8 @@
 #endif
 
 static const Jim_Nvp nvp_jtag_tap_event[] = {
+       { .value = JTAG_TRST_ASSERTED,          .name = "post-reset" },
+       { .value = JTAG_TAP_EVENT_SETUP,        .name = "setup" },
        { .value = JTAG_TAP_EVENT_ENABLE,       .name = "tap-enable" },
        { .value = JTAG_TAP_EVENT_DISABLE,      .name = "tap-disable" },
 
@@ -55,10 +57,13 @@ static int handle_interface_list_command(struct command_context_s *cmd_ctx,
 static int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_khz_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+static int handle_jtag_rclk_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+static int handle_jtag_nsrst_assert_width_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+static int handle_jtag_ntrst_assert_width_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 static int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
@@ -73,8 +78,6 @@ static int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, ch
 static int handle_verify_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_tms_sequence_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
-extern int jtag_examine_chain(void);
-extern int jtag_validate_chain(void);
 
 enum jtag_tap_cfg_param {
        JCFG_EVENT
@@ -140,9 +143,11 @@ static int jtag_tap_configure_cmd(Jim_GetOptInfo *goi, jtag_tap_t * tap)
                                        }
 
                                        if (goi->isconfigure) {
+                                               bool replace = true;
                                                if (jteap == NULL) {
                                                        /* create new */
                                                        jteap = calloc(1, sizeof (*jteap));
+                                                       replace = false;
                                                }
                                                jteap->event = n->value;
                                                Jim_GetOpt_Obj(goi, &o);
@@ -152,9 +157,12 @@ static int jtag_tap_configure_cmd(Jim_GetOptInfo *goi, jtag_tap_t * tap)
                                                jteap->body = Jim_DuplicateObj(goi->interp, o);
                                                Jim_IncrRefCount(jteap->body);
 
-                                               /* add to head of event list */
-                                               jteap->next = tap->event_action;
-                                               tap->event_action = jteap;
+                                               if (!replace)
+                                               {
+                                                       /* add to head of event list */
+                                                       jteap->next = tap->event_action;
+                                                       tap->event_action = jteap;
+                                               }
                                                Jim_SetEmptyResult(goi->interp);
                                        } else {
                                                /* get */
@@ -219,6 +227,7 @@ static int jim_newtap_cmd(Jim_GetOptInfo *goi)
         * */
        if (goi->argc < 3) {
                Jim_SetResult_sprintf(goi->interp, "Missing CHIP TAP OPTIONS ....");
+               free(pTap);
                return JIM_ERR;
        }
        Jim_GetOpt_String(goi, &cp, NULL);
@@ -236,18 +245,22 @@ static int jim_newtap_cmd(Jim_GetOptInfo *goi)
        LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params",
                          pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc);
 
-       /* deal with options */
-#define NTREQ_IRLEN      1
-#define NTREQ_IRCAPTURE  2
-#define NTREQ_IRMASK     4
+       /* IEEE specifies that the two LSBs of an IR scan are 01, so make
+        * that the default.  The "-irlen" and "-irmask" options are only
+        * needed to cope with nonstandard TAPs, or to specify more bits.
+        */
+       pTap->ir_capture_mask = 0x03;
+       pTap->ir_capture_value = 0x01;
 
-       /* clear them as we find them */
-       reqbits = (NTREQ_IRLEN | NTREQ_IRCAPTURE | NTREQ_IRMASK);
+       /* clear flags for "required options" them as we find them */
+       reqbits = 1;
 
        while (goi->argc) {
                e = Jim_GetOpt_Nvp(goi, opts, &n);
                if (e != JIM_OK) {
                        Jim_GetOpt_NvpUnknown(goi, opts, 0);
+                       free((void *)pTap->dotted_name);
+                       free(pTap);
                        return e;
                }
                LOG_DEBUG("Processing option: %s", n->name);
@@ -265,12 +278,16 @@ static int jim_newtap_cmd(Jim_GetOptInfo *goi)
                        e = Jim_GetOpt_Wide(goi, &w);
                        if (e != JIM_OK) {
                                Jim_SetResult_sprintf(goi->interp, "option: %s bad parameter", n->name);
+                               free((void *)pTap->dotted_name);
+                               free(pTap);
                                return e;
                        }
 
                        new_expected_ids = malloc(sizeof(uint32_t) * (pTap->expected_ids_cnt + 1));
                        if (new_expected_ids == NULL) {
                                Jim_SetResult_sprintf(goi->interp, "no memory");
+                               free((void *)pTap->dotted_name);
+                               free(pTap);
                                return JIM_ERR;
                        }
 
@@ -289,32 +306,46 @@ static int jim_newtap_cmd(Jim_GetOptInfo *goi)
                        e = Jim_GetOpt_Wide(goi, &w);
                        if (e != JIM_OK) {
                                Jim_SetResult_sprintf(goi->interp, "option: %s bad parameter", n->name);
+                               free((void *)pTap->dotted_name);
+                               free(pTap);
                                return e;
                        }
                        switch (n->value) {
                        case NTAP_OPT_IRLEN:
                                if (w > (jim_wide) (8 * sizeof(pTap->ir_capture_value)))
-                                       LOG_WARNING("huge IR length %d", (int) w);
+                                       LOG_WARNING("%s: huge IR length %d",
+                                                       pTap->dotted_name,
+                                                       (int) w);
                                pTap->ir_length = w;
-                               reqbits &= (~(NTREQ_IRLEN));
+                               reqbits = 0;
                                break;
                        case NTAP_OPT_IRMASK:
                                if (is_bad_irval(pTap->ir_length, w)) {
-                                       LOG_ERROR("IR mask %x too big",
+                                       LOG_ERROR("%s: IR mask %x too big",
+                                                       pTap->dotted_name,
                                                        (int) w);
+                                       free((void *)pTap->dotted_name);
+                                       free(pTap);
                                        return ERROR_FAIL;
                                }
+                               if ((w & 3) != 3)
+                                       LOG_WARNING("%s: nonstandard IR mask",
+                                                       pTap->dotted_name);
                                pTap->ir_capture_mask = w;
-                               reqbits &= (~(NTREQ_IRMASK));
                                break;
                        case NTAP_OPT_IRCAPTURE:
                                if (is_bad_irval(pTap->ir_length, w)) {
-                                       LOG_ERROR("IR capture %x too big",
+                                       LOG_ERROR("%s: IR capture %x too big",
+                                                       pTap->dotted_name,
                                                        (int) w);
+                                       free((void *)pTap->dotted_name);
+                                       free(pTap);
                                        return ERROR_FAIL;
                                }
+                               if ((w & 3) != 1)
+                                       LOG_WARNING("%s: nonstandard IR value",
+                                                       pTap->dotted_name);
                                pTap->ir_capture_value = w;
-                               reqbits &= (~(NTREQ_IRCAPTURE));
                                break;
                        }
                } /* switch (n->value) */
@@ -340,37 +371,31 @@ static int jim_newtap_cmd(Jim_GetOptInfo *goi)
 static void jtag_tap_handle_event(jtag_tap_t *tap, enum jtag_event e)
 {
        jtag_tap_event_action_t * jteap;
-       int done;
 
-       jteap = tap->event_action;
-
-       done = 0;
-       while (jteap) {
+       for (jteap = tap->event_action; jteap != NULL; jteap = jteap->next) {
                if (jteap->event == e) {
-                       done = 1;
-                       LOG_DEBUG("JTAG tap: %s event: %d (%s) action: %s\n",
+                       LOG_DEBUG("JTAG tap: %s event: %d (%s)\n\taction: %s",
                                        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);
-                       } else {
+                       } else switch (e) {
+                       case JTAG_TAP_EVENT_ENABLE:
+                       case JTAG_TAP_EVENT_DISABLE:
                                /* NOTE:  we currently assume the handlers
-                                * can't fail.  That presumes later code
-                                * will be verifying the scan chains ...
+                                * can't fail.  Right here is where we should
+                                * really be verifying the scan chains ...
                                 */
                                tap->enabled = (e == JTAG_TAP_EVENT_ENABLE);
+                               LOG_INFO("JTAG tap: %s %s", tap->dotted_name,
+                                       tap->enabled ? "enabled" : "disabled");
+                               break;
+                       default:
+                               break;
                        }
                }
-
-               jteap = jteap->next;
-       }
-
-       if (!done) {
-               LOG_DEBUG("event %d %s - no action",
-                               e,
-                               Jim_Nvp_value2name_simple(nvp_jtag_tap_event, e)->name);
        }
 }
 
@@ -391,7 +416,8 @@ static int jim_jtag_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                JTAG_CMD_TAPDISABLE,
                JTAG_CMD_TAPISENABLED,
                JTAG_CMD_CONFIGURE,
-               JTAG_CMD_CGET
+               JTAG_CMD_CGET,
+               JTAG_CMD_NAMES,
        };
 
        const Jim_Nvp jtag_cmds[] = {
@@ -403,6 +429,7 @@ static int jim_jtag_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                { .name = "tapdisable"    , .value = JTAG_CMD_TAPDISABLE },
                { .name = "configure"     , .value = JTAG_CMD_CONFIGURE },
                { .name = "cget"          , .value = JTAG_CMD_CGET },
+               { .name = "names"         , .value = JTAG_CMD_NAMES },
 
                { .name = NULL, .value = -1 },
        };
@@ -497,7 +524,8 @@ static int jim_jtag_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
        case JTAG_CMD_CGET:
                if (goi.argc < 2) {
-                       Jim_WrongNumArgs(goi.interp, 0, NULL, "?tap-name? -option ...");
+                       Jim_WrongNumArgs(goi.interp, 0, NULL,
+                                       "cget tap_name queryparm");
                        return JIM_ERR;
                }
 
@@ -517,7 +545,8 @@ static int jim_jtag_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
        case JTAG_CMD_CONFIGURE:
                if (goi.argc < 3) {
-                       Jim_WrongNumArgs(goi.interp, 0, NULL, "?tap-name? -option ?VALUE? ...");
+                       Jim_WrongNumArgs(goi.interp, 0, NULL,
+                                       "configure tap_name attribute value ...");
                        return JIM_ERR;
                }
 
@@ -533,11 +562,42 @@ static int jim_jtag_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                        goi.isconfigure = 1;
                        return jtag_tap_configure_cmd(&goi, t);
                }
+               break;
+
+       case JTAG_CMD_NAMES:
+               if (goi.argc != 0) {
+                       Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters");
+                       return JIM_ERR;
+               }
+               Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0));
+               {
+                       jtag_tap_t *tap;
+
+                       for (tap = jtag_all_taps(); tap; tap = tap->next_tap) {
+                               Jim_ListAppendElement(goi.interp,
+                                       Jim_GetResult(goi.interp),
+                                       Jim_NewStringObj(goi.interp,
+                                               tap->dotted_name, -1));
+                       }
+                       return JIM_OK;
+               }
+               break;
+
        }
 
        return JIM_ERR;
 }
 
+
+void jtag_notify_event(enum jtag_event event)
+{
+       jtag_tap_t *tap;
+
+       for (tap = jtag_all_taps(); tap; tap = tap->next_tap)
+               jtag_tap_handle_event(tap, event);
+}
+
+
 int jtag_register_commands(struct command_context_s *cmd_ctx)
 {
        register_jim(cmd_ctx, "jtag", jim_jtag_command, "perform jtag tap actions");
@@ -552,6 +612,8 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx, NULL, "jtag_khz", handle_jtag_khz_command,
                COMMAND_ANY, "set maximum jtag speed (if supported); "
                "parameter is maximum khz, or 0 for adaptive clocking (RTCK).");
+       register_command(cmd_ctx, NULL, "jtag_rclk", handle_jtag_rclk_command,
+               COMMAND_ANY, "fallback_speed_khz - set JTAG speed to RCLK or use fallback speed");
        register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command,
                COMMAND_CONFIG, "(DEPRECATED) jtag_device <ir_length> <ir_expected> <ir_mask>");
        register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
@@ -561,6 +623,10 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
                COMMAND_ANY, "jtag_nsrst_delay <ms> - delay after deasserting srst in ms");
        register_command(cmd_ctx, NULL, "jtag_ntrst_delay", handle_jtag_ntrst_delay_command,
                COMMAND_ANY, "jtag_ntrst_delay <ms> - delay after deasserting trst in ms");
+       register_command(cmd_ctx, NULL, "jtag_nsrst_assert_width", handle_jtag_nsrst_assert_width_command,
+               COMMAND_ANY, "jtag_nsrst_assert_width <ms> - delay after asserting srst in ms");
+       register_command(cmd_ctx, NULL, "jtag_ntrst_assert_width", handle_jtag_ntrst_assert_width_command,
+               COMMAND_ANY, "jtag_ntrst_assert_width <ms> - delay after asserting trst in ms");
 
        register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command,
                COMMAND_EXEC, "print current scan chain configuration");
@@ -786,6 +852,14 @@ static int handle_reset_config_command(struct command_context_s *cmd_ctx, char *
                int tmp = 0;
                int m;
 
+               m = RESET_SRST_GATES_JTAG;
+               tmp = 0;
+               if (strcmp(*args, "srst_gates_jtag") == 0)
+               {
+                       tmp = RESET_SRST_GATES_JTAG;
+                       goto next;
+               }
+
                /* signals */
                m = RESET_HAS_TRST | RESET_HAS_SRST;
                if (strcmp(*args, "none") == 0)
@@ -913,10 +987,47 @@ static int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx,
        return ERROR_OK;
 }
 
+static int handle_jtag_nsrst_assert_width_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
+{
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (argc == 1)
+       {
+               unsigned delay;
+               int retval = parse_uint(args[0], &delay);
+               if (ERROR_OK != retval)
+                       return retval;
+               jtag_set_nsrst_assert_width(delay);
+       }
+       command_print(cmd_ctx, "jtag_nsrst_assert_width: %u", jtag_get_nsrst_assert_width());
+       return ERROR_OK;
+}
+
+static int handle_jtag_ntrst_assert_width_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
+{
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (argc == 1)
+       {
+               unsigned delay;
+               int retval = parse_uint(args[0], &delay);
+               if (ERROR_OK != retval)
+                       return retval;
+               jtag_set_ntrst_assert_width(delay);
+       }
+       command_print(cmd_ctx, "jtag_ntrst_assert_width: %u", jtag_get_ntrst_assert_width());
+       return ERROR_OK;
+}
+
 static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
        int retval = ERROR_OK;
 
+       command_print(cmd_ctx, "OLD SYNTAX: DEPRECATED - "
+                       "use jtag_khz, not jtag_speed");
+
        if (argc > 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
        if (argc == 1)
@@ -927,7 +1038,7 @@ static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cm
                int retval = parse_uint(args[0], &cur_speed);
                if (ERROR_OK != retval)
                        return retval;
-               retval = jtag_set_speed(cur_speed);
+               retval = jtag_config_speed(cur_speed);
 
        }
        command_print(cmd_ctx, "jtag_speed: %d", jtag_get_speed());
@@ -965,6 +1076,36 @@ static int handle_jtag_khz_command(struct command_context_s *cmd_ctx, char *cmd,
        return retval;
 }
 
+static int handle_jtag_rclk_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       int retval = ERROR_OK;
+       if (argc == 1)
+       {
+               unsigned khz = 0;
+               int retval = parse_uint(args[0], &khz);
+               if (ERROR_OK != retval)
+                       return retval;
+               retval = jtag_config_rclk(khz);
+               if (ERROR_OK != retval)
+                       return retval;
+       }
+
+       int cur_khz = jtag_get_speed_khz();
+       retval = jtag_get_speed_readable(&cur_khz);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (cur_khz)
+               command_print(cmd_ctx, "RCLK not supported - fallback to %d kHz", cur_khz);
+       else
+               command_print(cmd_ctx, "RCLK - adaptive");
+
+       return retval;
+}
+
 static int handle_jtag_reset_command(struct command_context_s *cmd_ctx,
                char *cmd, char **args, int argc)
 {
@@ -991,9 +1132,7 @@ static int handle_jtag_reset_command(struct command_context_s *cmd_ctx,
                return ERROR_JTAG_INIT_FAILED;
 
        jtag_add_reset(trst, srst);
-       jtag_execute_queue();
-
-       return ERROR_OK;
+       return jtag_execute_queue();
 }
 
 static int handle_runtest_command(struct command_context_s *cmd_ctx,
@@ -1008,9 +1147,7 @@ static int handle_runtest_command(struct command_context_s *cmd_ctx,
                return retval;
 
        jtag_add_runtest(num_clocks, TAP_IDLE);
-       jtag_execute_queue();
-
-       return ERROR_OK;
+       return jtag_execute_queue();
 }
 
 /*
@@ -1087,7 +1224,12 @@ static int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, c
                tap = jtag_tap_by_string(args[i*2]);
                if (tap == NULL)
                {
+                       int j;
+                       for (j = 0; j < i; j++)
+                               free(fields[j].out_value);
+                        free(fields);
                        command_print(cmd_ctx, "Tap: %s unknown", args[i*2]);
+
                        return ERROR_FAIL;
                }
                int field_size = tap->ir_length;