From d60ebc0ab535e54f76e734d00d9ac1b5c9b6eb93 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 27 Mar 2010 10:07:13 -0700 Subject: jtag/tcl.c cleanup -- split out "adapter.c" Clean up the jtag/tcl.c file, which was one of the biggest and messiest ones in that directory. Do it by splitting out all the generic adapter commands to a separate "adapter.c" file (leaving the "tcl.c" file holding only JTAG utilities). Also rename the little-used "jtag interface" to "adapter_name", which should have been at least re-categorized earlier (it's not jtag-only). Signed-off-by: David Brownell --- src/jtag/adapter.c | 459 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 src/jtag/adapter.c (limited to 'src/jtag/adapter.c') diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c new file mode 100644 index 00000000..b262a9a7 --- /dev/null +++ b/src/jtag/adapter.c @@ -0,0 +1,459 @@ +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * Copyright (C) 2007-2010 Øyvind Harboe * + * oyvind.harboe@zylin.com * + * * + * Copyright (C) 2009 SoftPLC Corporation * + * http://softplc.com * + * dick@softplc.com * + * * + * Copyright (C) 2009 Zachary T Welch * + * zw@superlucidity.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "jtag.h" +#include "minidriver.h" +#include "interface.h" +#include "interfaces.h" + +#ifdef HAVE_STRINGS_H +#include +#endif + +/** + * @file + * Holds support for configuring debug adapters from TCl scripts. + */ + +extern struct jtag_interface *jtag_interface; + + + +static int +jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); + + /* return the name of the interface */ + /* TCL code might need to know the exact type... */ + /* FUTURE: we allow this as a means to "set" the interface. */ + if (goi.argc != 0) { + Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); + return JIM_ERR; + } + const char *name = jtag_interface ? jtag_interface->name : NULL; + Jim_SetResultString(goi.interp, name ? : "undefined", -1); + return JIM_OK; +} + + +static int default_khz(int khz, int *jtag_speed) +{ + LOG_ERROR("Translation from khz to jtag_speed not implemented"); + return ERROR_FAIL; +} + +static int default_speed_div(int speed, int *khz) +{ + LOG_ERROR("Translation from jtag_speed to khz not implemented"); + return ERROR_FAIL; +} + +static int default_power_dropout(int *dropout) +{ + *dropout = 0; /* by default we can't detect power dropout */ + return ERROR_OK; +} + +static int default_srst_asserted(int *srst_asserted) +{ + *srst_asserted = 0; /* by default we can't detect srst asserted */ + return ERROR_OK; +} + +COMMAND_HANDLER(handle_interface_list_command) +{ + if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, "The following debug interfaces are available:"); + for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) + { + const char *name = jtag_interfaces[i]->name; + command_print(CMD_CTX, "%u: %s", i + 1, name); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_interface_command) +{ + /* check whether the interface is already configured */ + if (jtag_interface) + { + LOG_WARNING("Interface already configured, ignoring"); + return ERROR_OK; + } + + /* interface name is a mandatory argument */ + if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) + { + if (strcmp(CMD_ARGV[0], jtag_interfaces[i]->name) != 0) + continue; + + if (NULL != jtag_interfaces[i]->commands) + { + int retval = register_commands(CMD_CTX, NULL, + jtag_interfaces[i]->commands); + if (ERROR_OK != retval) + return retval; + } + + jtag_interface = jtag_interfaces[i]; + + if (jtag_interface->khz == NULL) + jtag_interface->khz = default_khz; + if (jtag_interface->speed_div == NULL) + jtag_interface->speed_div = default_speed_div; + if (jtag_interface->power_dropout == NULL) + jtag_interface->power_dropout = default_power_dropout; + if (jtag_interface->srst_asserted == NULL) + jtag_interface->srst_asserted = default_srst_asserted; + + return ERROR_OK; + } + + /* no valid interface was found (i.e. the configuration option, + * didn't match one of the compiled-in interfaces + */ + LOG_ERROR("The specified debug interface was not found (%s)", CMD_ARGV[0]); + CALL_COMMAND_HANDLER(handle_interface_list_command); + return ERROR_JTAG_INVALID_INTERFACE; +} + +COMMAND_HANDLER(handle_reset_config_command) +{ + int new_cfg = 0; + int mask = 0; + + /* Original versions cared about the order of these tokens: + * reset_config signals [combination [trst_type [srst_type]]] + * They also clobbered the previous configuration even on error. + * + * Here we don't care about the order, and only change values + * which have been explicitly specified. + */ + for (; CMD_ARGC; CMD_ARGC--, CMD_ARGV++) { + int tmp = 0; + int m; + + /* gating */ + m = RESET_SRST_NO_GATING; + if (strcmp(*CMD_ARGV, "srst_gates_jtag") == 0) + /* default: don't use JTAG while SRST asserted */; + else if (strcmp(*CMD_ARGV, "srst_nogate") == 0) + tmp = RESET_SRST_NO_GATING; + else + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "gating", *CMD_ARGV); + return ERROR_INVALID_ARGUMENTS; + } + if (m) + goto next; + + /* signals */ + m = RESET_HAS_TRST | RESET_HAS_SRST; + if (strcmp(*CMD_ARGV, "none") == 0) + tmp = RESET_NONE; + else if (strcmp(*CMD_ARGV, "trst_only") == 0) + tmp = RESET_HAS_TRST; + else if (strcmp(*CMD_ARGV, "srst_only") == 0) + tmp = RESET_HAS_SRST; + else if (strcmp(*CMD_ARGV, "trst_and_srst") == 0) + tmp = RESET_HAS_TRST | RESET_HAS_SRST; + else + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "signal", *CMD_ARGV); + return ERROR_INVALID_ARGUMENTS; + } + if (m) + goto next; + + /* combination (options for broken wiring) */ + m = RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; + if (strcmp(*CMD_ARGV, "separate") == 0) + /* separate reset lines - default */; + else if (strcmp(*CMD_ARGV, "srst_pulls_trst") == 0) + tmp |= RESET_SRST_PULLS_TRST; + else if (strcmp(*CMD_ARGV, "trst_pulls_srst") == 0) + tmp |= RESET_TRST_PULLS_SRST; + else if (strcmp(*CMD_ARGV, "combined") == 0) + tmp |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; + else + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "combination", *CMD_ARGV); + return ERROR_INVALID_ARGUMENTS; + } + if (m) + goto next; + + /* trst_type (NOP without HAS_TRST) */ + m = RESET_TRST_OPEN_DRAIN; + if (strcmp(*CMD_ARGV, "trst_open_drain") == 0) + tmp |= RESET_TRST_OPEN_DRAIN; + else if (strcmp(*CMD_ARGV, "trst_push_pull") == 0) + /* push/pull from adapter - default */; + else + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "trst_type", *CMD_ARGV); + return ERROR_INVALID_ARGUMENTS; + } + if (m) + goto next; + + /* srst_type (NOP without HAS_SRST) */ + m |= RESET_SRST_PUSH_PULL; + if (strcmp(*CMD_ARGV, "srst_push_pull") == 0) + tmp |= RESET_SRST_PUSH_PULL; + else if (strcmp(*CMD_ARGV, "srst_open_drain") == 0) + /* open drain from adapter - default */; + else + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "srst_type", *CMD_ARGV); + return ERROR_INVALID_ARGUMENTS; + } + if (m) + goto next; + + /* caller provided nonsense; fail */ + LOG_ERROR("unknown reset_config flag (%s)", *CMD_ARGV); + return ERROR_INVALID_ARGUMENTS; + +next: + /* Remember the bits which were specified (mask) + * and their new values (new_cfg). + */ + mask |= m; + new_cfg |= tmp; + } + + /* clear previous values of those bits, save new values */ + if (mask) { + int old_cfg = jtag_get_reset_config(); + + old_cfg &= ~mask; + new_cfg |= old_cfg; + jtag_set_reset_config(new_cfg); + } else + new_cfg = jtag_get_reset_config(); + + + /* + * Display the (now-)current reset mode + */ + char *modes[5]; + + /* minimal JTAG has neither SRST nor TRST (so that's the default) */ + switch (new_cfg & (RESET_HAS_TRST | RESET_HAS_SRST)) { + case RESET_HAS_SRST: + modes[0] = "srst_only"; + break; + case RESET_HAS_TRST: + modes[0] = "trst_only"; + break; + case RESET_TRST_AND_SRST: + modes[0] = "trst_and_srst"; + break; + default: + modes[0] = "none"; + break; + } + + /* normally SRST and TRST are decoupled; but bugs happen ... */ + switch (new_cfg & (RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST)) { + case RESET_SRST_PULLS_TRST: + modes[1] = "srst_pulls_trst"; + break; + case RESET_TRST_PULLS_SRST: + modes[1] = "trst_pulls_srst"; + break; + case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: + modes[1] = "combined"; + break; + default: + modes[1] = "separate"; + break; + } + + /* TRST-less connectors include Altera, Xilinx, and minimal JTAG */ + if (new_cfg & RESET_HAS_TRST) { + if (new_cfg & RESET_TRST_OPEN_DRAIN) + modes[3] = " trst_open_drain"; + else + modes[3] = " trst_push_pull"; + } else + modes[3] = ""; + + /* SRST-less connectors include TI-14, Xilinx, and minimal JTAG */ + if (new_cfg & RESET_HAS_SRST) { + if (new_cfg & RESET_SRST_NO_GATING) + modes[2] = " srst_nogate"; + else + modes[2] = " srst_gates_jtag"; + + if (new_cfg & RESET_SRST_PUSH_PULL) + modes[4] = " srst_push_pull"; + else + modes[4] = " srst_open_drain"; + } else { + modes[2] = ""; + modes[4] = ""; + } + + command_print(CMD_CTX, "%s %s%s%s%s", + modes[0], modes[1], + modes[2], modes[3], modes[4]); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_adapter_nsrst_delay_command) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGC == 1) + { + unsigned delay; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); + + jtag_set_nsrst_delay(delay); + } + command_print(CMD_CTX, "adapter_nsrst_delay: %u", jtag_get_nsrst_delay()); + return ERROR_OK; +} + +COMMAND_HANDLER(handle_adapter_khz_command) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + int retval = ERROR_OK; + if (CMD_ARGC == 1) + { + unsigned khz = 0; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); + + retval = jtag_config_khz(khz); + if (ERROR_OK != retval) + return retval; + } + + int cur_speed = jtag_get_speed_khz(); + retval = jtag_get_speed_readable(&cur_speed); + if (ERROR_OK != retval) + return retval; + + if (cur_speed) + command_print(CMD_CTX, "%d kHz", cur_speed); + else + command_print(CMD_CTX, "RCLK - adaptive"); + + return retval; +} + +static const struct command_registration interface_command_handlers[] = { + { + .name = "adapter_khz", + .handler = handle_adapter_khz_command, + .mode = COMMAND_ANY, + .help = "With an argument, change to the specified maximum " + "jtag speed. For JTAG, 0 KHz signifies adaptive " + " clocking. " + "With or without argument, display current setting.", + .usage = "[khz]", + }, + { + .name = "adapter_name", + .mode = COMMAND_ANY, + .jim_handler = jim_adapter_name, + .help = "Returns the name of the currently " + "selected adapter (driver)", + }, + { + .name = "adapter_nsrst_delay", + .handler = handle_adapter_nsrst_delay_command, + .mode = COMMAND_ANY, + .help = "delay after deasserting SRST in ms", + .usage = "[milliseconds]", + }, + { + .name = "interface", + .handler = handle_interface_command, + .mode = COMMAND_CONFIG, + .help = "Select a debug adapter interface (driver)", + .usage = "driver_name", + }, + { + .name = "interface_list", + .handler = handle_interface_list_command, + .mode = COMMAND_ANY, + .help = "List all built-in debug adapter interfaces (drivers)", + }, + { + .name = "reset_config", + .handler = handle_reset_config_command, + .mode = COMMAND_ANY, + .help = "configure adapter reset behavior", + .usage = "[none|trst_only|srst_only|trst_and_srst] " + "[srst_pulls_trst|trst_pulls_srst|combined|separate] " + "[srst_gates_jtag|srst_nogate] " + "[trst_push_pull|trst_open_drain] " + "[srst_push_pull|srst_open_drain]", + }, + COMMAND_REGISTRATION_DONE +}; + +/** + * Register the commands which deal with arbitrary debug adapter drivers. + * + * @todo Remove internal assumptions that all debug adapters use JTAG for + * transport. Various types and data structures are not named generically. + */ +int interface_register_commands(struct command_context *ctx) +{ + return register_commands(ctx, NULL, interface_command_handlers); +} -- cgit v1.2.3