X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fadapter.c;h=af75917a32d795471aed41c4887e7202fc56055f;hp=a5a6222a9190d0017191ec6eb5b1f5e19c5b124e;hb=HEAD;hpb=ac1a632ba13efa77393cecf29bd29410db60cada diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index a5a6222a91..bbf1cb3d2e 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2005 by Dominic Rath * Copyright (C) 2007-2010 Øyvind Harboe @@ -18,10 +18,6 @@ #include "interfaces.h" #include -#ifdef HAVE_STRINGS_H -#include -#endif - /** * @file * Holds support for configuring debug adapters from TCl scripts. @@ -36,22 +32,87 @@ enum adapter_clk_mode { CLOCK_MODE_RCLK }; +#define DEFAULT_CLOCK_SPEED_KHZ 100U + /** * Adapter configuration */ static struct { bool adapter_initialized; char *usb_location; + char *serial; enum adapter_clk_mode clock_mode; int speed_khz; int rclk_fallback_speed_khz; + struct adapter_gpio_config gpios[ADAPTER_GPIO_IDX_NUM]; + bool gpios_initialized; /* Initialization of GPIOs to their unset values performed at run time */ } adapter_config; +static const struct gpio_map { + const char *name; + enum adapter_gpio_direction direction; + bool permit_drive_option; + bool permit_init_state_option; +} gpio_map[ADAPTER_GPIO_IDX_NUM] = { + [ADAPTER_GPIO_IDX_TDO] = { "tdo", ADAPTER_GPIO_DIRECTION_INPUT, false, true, }, + [ADAPTER_GPIO_IDX_TDI] = { "tdi", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TMS] = { "tms", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TCK] = { "tck", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_SWDIO] = { "swdio", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, }, + [ADAPTER_GPIO_IDX_SWDIO_DIR] = { "swdio_dir", ADAPTER_GPIO_DIRECTION_OUTPUT, true, false, }, + [ADAPTER_GPIO_IDX_SWCLK] = { "swclk", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TRST] = { "trst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, + [ADAPTER_GPIO_IDX_SRST] = { "srst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, + [ADAPTER_GPIO_IDX_LED] = { "led", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, +}; + bool is_adapter_initialized(void) { return adapter_config.adapter_initialized; } +/* For convenience of the bit-banging drivers keep the gpio_config drive + * settings for srst and trst in sync with values set by the "adapter + * reset_config" command. + */ +static void sync_adapter_reset_with_gpios(void) +{ + enum reset_types cfg = jtag_get_reset_config(); + if (cfg & RESET_SRST_PUSH_PULL) + adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; + else + adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; + if (cfg & RESET_TRST_OPEN_DRAIN) + adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; + else + adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; +} + +static void adapter_driver_gpios_init(void) +{ + if (adapter_config.gpios_initialized) + return; + + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) { + /* Use ADAPTER_GPIO_NOT_SET as the sentinel 'unset' value. */ + adapter_config.gpios[i].gpio_num = ADAPTER_GPIO_NOT_SET; + adapter_config.gpios[i].chip_num = ADAPTER_GPIO_NOT_SET; + if (gpio_map[i].direction == ADAPTER_GPIO_DIRECTION_INPUT) + adapter_config.gpios[i].init_state = ADAPTER_GPIO_INIT_STATE_INPUT; + } + + /* Drivers assume active low, and this is the normal behaviour for reset + * lines so should be the default. */ + adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].active_low = true; + adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].active_low = true; + sync_adapter_reset_with_gpios(); + + /* JTAG GPIOs should be inactive except for tms */ + adapter_config.gpios[ADAPTER_GPIO_IDX_TMS].init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE; + + adapter_config.gpios_initialized = true; +} + /** * Do low-level setup like initializing registers, output signals, * and clocking. @@ -68,23 +129,33 @@ int adapter_init(struct command_context *cmd_ctx) return ERROR_JTAG_INVALID_INTERFACE; } + adapter_driver_gpios_init(); + int retval; + + /* If the adapter supports configurable speed but the speed is not configured, + * provide a hint to the user. */ + if (adapter_driver->speed && adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) { + LOG_WARNING("An adapter speed is not selected in the init scripts." + " OpenOCD will try to run the adapter at very low speed (%d kHz).", + DEFAULT_CLOCK_SPEED_KHZ); + LOG_WARNING("To remove this warnings and achieve reasonable communication speed with the target," + " set \"adapter speed\" or \"jtag_rclk\" in the init scripts."); + retval = adapter_config_khz(DEFAULT_CLOCK_SPEED_KHZ); + if (retval != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + } + retval = adapter_driver->init(); if (retval != ERROR_OK) return retval; adapter_config.adapter_initialized = true; if (!adapter_driver->speed) { - LOG_INFO("This adapter doesn't support configurable speed"); + LOG_INFO("Note: The adapter \"%s\" doesn't support configurable speed", adapter_driver->name); return ERROR_OK; } - if (adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) { - LOG_ERROR("An adapter speed is not selected in the init script." - " Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed."); - return ERROR_JTAG_INIT_FAILED; - } - int requested_khz = adapter_get_speed_khz(); int actual_khz = requested_khz; int speed_var = 0; @@ -120,6 +191,9 @@ int adapter_quit(void) LOG_ERROR("failed: %d", result); } + free(adapter_config.serial); + free(adapter_config.usb_location); + struct jtag_tap *t = jtag_all_taps(); while (t) { struct jtag_tap *n = t->next_tap; @@ -221,6 +295,11 @@ int adapter_get_speed_readable(int *khz) return adapter_driver->speed_div(speed_var, khz); } +const char *adapter_get_required_serial(void) +{ + return adapter_config.serial; +} + /* * 1 char: bus * 2 * 7 chars: max 7 ports @@ -296,21 +375,18 @@ done: return equal; } -static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_adapter_name) { - struct jim_getopt_info 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 = adapter_driver ? adapter_driver->name : NULL; - Jim_SetResultString(goi.interp, name ? name : "undefined", -1); - return JIM_OK; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD, "%s", adapter_driver ? adapter_driver->name : "undefined"); + + return ERROR_OK; } COMMAND_HANDLER(adapter_transports_command) @@ -365,8 +441,7 @@ COMMAND_HANDLER(handle_adapter_driver_command) continue; if (adapter_drivers[i]->commands) { - retval = register_commands(CMD_CTX, NULL, - adapter_drivers[i]->commands); + retval = register_commands(CMD_CTX, NULL, adapter_drivers[i]->commands); if (retval != ERROR_OK) return retval; } @@ -524,6 +599,8 @@ next: old_cfg &= ~mask; new_cfg |= old_cfg; jtag_set_reset_config(new_cfg); + sync_adapter_reset_with_gpios(); + } else new_cfg = jtag_get_reset_config(); @@ -658,6 +735,16 @@ COMMAND_HANDLER(handle_adapter_speed_command) return retval; } +COMMAND_HANDLER(handle_adapter_serial_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(adapter_config.serial); + adapter_config.serial = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + COMMAND_HANDLER(handle_adapter_reset_de_assert) { enum values { @@ -744,6 +831,219 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert) (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); } +static int get_gpio_index(const char *signal_name) +{ + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) { + if (strcmp(gpio_map[i].name, signal_name) == 0) + return i; + } + return -1; +} + +static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config_index gpio_idx) +{ + struct adapter_gpio_config *gpio_config = &adapter_config.gpios[gpio_idx]; + const char *active_state = gpio_config->active_low ? "low" : "high"; + const char *dir = ""; + const char *drive = ""; + const char *pull = ""; + const char *init_state = ""; + + if (gpio_config->gpio_num == ADAPTER_GPIO_NOT_SET) { + command_print(CMD, "adapter gpio %s: not configured", gpio_map[gpio_idx].name); + return ERROR_OK; + } + + switch (gpio_map[gpio_idx].direction) { + case ADAPTER_GPIO_DIRECTION_INPUT: + dir = "input"; + break; + case ADAPTER_GPIO_DIRECTION_OUTPUT: + dir = "output"; + break; + case ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL: + dir = "bidirectional"; + break; + } + + if (gpio_map[gpio_idx].permit_drive_option) { + switch (gpio_config->drive) { + case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + drive = ", push-pull"; + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: + drive = ", open-drain"; + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: + drive = ", open-source"; + break; + } + } + + switch (gpio_config->pull) { + case ADAPTER_GPIO_PULL_NONE: + pull = ", pull-none"; + break; + case ADAPTER_GPIO_PULL_UP: + pull = ", pull-up"; + break; + case ADAPTER_GPIO_PULL_DOWN: + pull = ", pull-down"; + break; + } + + if (gpio_map[gpio_idx].permit_init_state_option) { + switch (gpio_config->init_state) { + case ADAPTER_GPIO_INIT_STATE_INACTIVE: + init_state = ", init-state inactive"; + break; + case ADAPTER_GPIO_INIT_STATE_ACTIVE: + init_state = ", init-state active"; + break; + case ADAPTER_GPIO_INIT_STATE_INPUT: + init_state = ", init-state input"; + break; + } + } + + command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%s%s%s", + gpio_map[gpio_idx].name, dir, gpio_config->gpio_num, (int)gpio_config->chip_num, active_state, + drive, pull, init_state); + + return ERROR_OK; +} + +COMMAND_HANDLER(helper_adapter_gpio_print_all_configs) +{ + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) + CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, i); + return ERROR_OK; +} + +COMMAND_HANDLER(adapter_gpio_config_handler) +{ + unsigned int i = 1; + struct adapter_gpio_config *gpio_config; + + adapter_driver_gpios_init(); + + if (CMD_ARGC == 0) { + CALL_COMMAND_HANDLER(helper_adapter_gpio_print_all_configs); + return ERROR_OK; + } + + int gpio_idx = get_gpio_index(CMD_ARGV[0]); + if (gpio_idx == -1) { + LOG_ERROR("adapter has no gpio named %s", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC == 1) { + CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, gpio_idx); + return ERROR_OK; + } + + gpio_config = &adapter_config.gpios[gpio_idx]; + while (i < CMD_ARGC) { + LOG_DEBUG("Processing %s", CMD_ARGV[i]); + + if (isdigit(*CMD_ARGV[i])) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], gpio_config->gpio_num); + ++i; + continue; + } + + if (strcmp(CMD_ARGV[i], "-chip") == 0) { + if (CMD_ARGC - i < 2) { + LOG_ERROR("-chip option requires a parameter"); + return ERROR_FAIL; + } + LOG_DEBUG("-chip arg is %s", CMD_ARGV[i + 1]); + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i + 1], gpio_config->chip_num); + i += 2; + continue; + } + + if (strcmp(CMD_ARGV[i], "-active-high") == 0) { + ++i; + gpio_config->active_low = false; + continue; + } + if (strcmp(CMD_ARGV[i], "-active-low") == 0) { + ++i; + gpio_config->active_low = true; + continue; + } + + if (gpio_map[gpio_idx].permit_drive_option) { + if (strcmp(CMD_ARGV[i], "-push-pull") == 0) { + ++i; + gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; + continue; + } + if (strcmp(CMD_ARGV[i], "-open-drain") == 0) { + ++i; + gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; + continue; + } + if (strcmp(CMD_ARGV[i], "-open-source") == 0) { + ++i; + gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE; + continue; + } + } + + if (strcmp(CMD_ARGV[i], "-pull-none") == 0) { + ++i; + gpio_config->pull = ADAPTER_GPIO_PULL_NONE; + continue; + } + if (strcmp(CMD_ARGV[i], "-pull-up") == 0) { + ++i; + gpio_config->pull = ADAPTER_GPIO_PULL_UP; + continue; + } + if (strcmp(CMD_ARGV[i], "-pull-down") == 0) { + ++i; + gpio_config->pull = ADAPTER_GPIO_PULL_DOWN; + continue; + } + + if (gpio_map[gpio_idx].permit_init_state_option) { + if (strcmp(CMD_ARGV[i], "-init-inactive") == 0) { + ++i; + gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INACTIVE; + continue; + } + if (strcmp(CMD_ARGV[i], "-init-active") == 0) { + ++i; + gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE; + continue; + } + + if (gpio_map[gpio_idx].direction == ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL && + strcmp(CMD_ARGV[i], "-init-input") == 0) { + ++i; + gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INPUT; + continue; + } + } + + LOG_ERROR("illegal option for adapter %s %s: %s", + CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* Force swdio_dir init state to be compatible with swdio init state */ + if (gpio_idx == ADAPTER_GPIO_IDX_SWDIO) + adapter_config.gpios[ADAPTER_GPIO_IDX_SWDIO_DIR].init_state = + (gpio_config->init_state == ADAPTER_GPIO_INIT_STATE_INPUT) ? + ADAPTER_GPIO_INIT_STATE_INACTIVE : + ADAPTER_GPIO_INIT_STATE_ACTIVE; + + return ERROR_OK; +} + #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS COMMAND_HANDLER(handle_usb_location_command) { @@ -805,6 +1105,13 @@ static const struct command_registration adapter_command_handlers[] = { "With or without argument, display current setting.", .usage = "[khz]", }, + { + .name = "serial", + .handler = handle_adapter_serial_command, + .mode = COMMAND_CONFIG, + .help = "Set the serial number of the adapter", + .usage = "serial_string", + }, { .name = "list", .handler = handle_adapter_list_command, @@ -815,9 +1122,10 @@ static const struct command_registration adapter_command_handlers[] = { { .name = "name", .mode = COMMAND_ANY, - .jim_handler = jim_adapter_name, + .handler = handle_adapter_name, .help = "Returns the name of the currently " "selected adapter (driver)", + .usage = "", }, { .name = "srst", @@ -854,6 +1162,19 @@ static const struct command_registration adapter_command_handlers[] = { .help = "Controls SRST and TRST lines.", .usage = "|assert [srst|trst [deassert|assert srst|trst]]", }, + { + .name = "gpio", + .handler = adapter_gpio_config_handler, + .mode = COMMAND_CONFIG, + .help = "gpio adapter command group", + .usage = "[ tdo|tdi|tms|tck|trst|swdio|swdio_dir|swclk|srst|led" + "[gpio_number] " + "[-chip chip_number] " + "[-active-high|-active-low] " + "[-push-pull|-open-drain|-open-source] " + "[-pull-none|-pull-up|-pull-down]" + "[-init-inactive|-init-active|-init-input] ]", + }, COMMAND_REGISTRATION_DONE }; @@ -890,3 +1211,14 @@ int adapter_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, interface_command_handlers); } + +const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx) +{ + return gpio_map[idx].name; +} + +/* Allow drivers access to the GPIO configuration */ +const struct adapter_gpio_config *adapter_gpio_get_config(void) +{ + return adapter_config.gpios; +}