jtag/adapter: Add command 'adapter gpio' 67/6967/21
authorSteve Marple <stevemarple@googlemail.com>
Wed, 4 May 2022 21:51:48 +0000 (22:51 +0100)
committerAntonio Borneo <borneo.antonio@gmail.com>
Mon, 15 Aug 2022 13:24:22 +0000 (13:24 +0000)
Most adapters define their own commands to obtain the GPIO number and
other GPIO configuration information such as chip number, output drive
type, active high/low.

Define a general command 'adapter gpio' as replacement for the
driver-specific ones.

Change-Id: I1ca9ca94f0c7df5713172e9f62ffb0ad64e9ee97
Signed-off-by: Steve Marple <stevemarple@googlemail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6967
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
doc/openocd.texi
src/jtag/adapter.c
src/jtag/adapter.h
src/jtag/startup.tcl

index 995861d18c063c06d51b87d97c640a5cec901f4b..083f946c4f31fe3604131b17c56f63f9568a7fb5 100644 (file)
@@ -2412,7 +2412,57 @@ when external configuration (such as jumpering) changes what
 the hardware can support.
 @end deffn
 
+@anchor{adapter gpio}
+@deffn {Config Command} {adapter gpio [ @
+    @option{tdo} | @option{tdi} | @option{tms} | @option{tck} | @option{trst} | @
+    @option{swdio} | @option{swdio_dir} | @option{swclk} | @option{srst} | @
+    @option{led} @
+    [ @
+        gpio_number | @option{-chip} chip_number | @
+        @option{-active-high} | @option{-active-low} | @
+        @option{-push-pull} | @option{-open-drain} | @option{-open-source} | @
+        @option{-pull-none} | @option{-pull-up} | @option{-pull-down} | @
+        @option{-init-inactive} | @option{-init-active} | @option{-init-input} @
+    ] ]}
+
+Define the GPIO mapping that the adapter will use. The following signals can be
+defined:
 
+@itemize @minus
+@item @option{tdo}, @option{tdi}, @option{tms}, @option{tck}, @option{trst}:
+JTAG transport signals
+@item @option{swdio}, @option{swclk}: SWD transport signals
+@item @option{swdio_dir}: optional swdio buffer control signal
+@item @option{srst}: system reset signal
+@item @option{led}: optional activity led
+
+@end itemize
+
+Some adapters require that the GPIO chip number is set in addition to the GPIO
+number. The configuration options enable signals to be defined as active-high or
+active-low. The output drive mode can be set to push-pull, open-drain or
+open-source. Most adapters will have to emulate open-drain or open-source drive
+modes by switching between an input and output. Input and output signals can be
+instructed to use a pull-up or pull-down resistor, assuming it is supported by
+the adaptor driver and hardware. The initial state of outputs may also be set,
+"active" state means 1 for active-high outputs and 0 for active-low outputs.
+Bidirectional signals may also be initialized as an input. If the swdio signal
+is buffered the buffer direction can be controlled with the swdio_dir signal;
+the active state means that the buffer should be set as an output with respect
+to the adapter. The command options are cumulative with later commands able to
+override settings defined by earlier ones. The two commands @command{gpio led 7
+-active-high} and @command{gpio led -chip 1 -active-low} sent sequentially are
+equivalent to issuing the single command @command{gpio led 7 -chip 1
+-active-low}. It is not permissible to set the drive mode or initial state for
+signals which are inputs. The drive mode for the srst and trst signals must be
+set with the @command{adapter reset_config} command. It is not permissible to
+set the initial state of swdio_dir as it is derived from the initial state of
+swdio. The command @command{adapter gpio} prints the current configuration for
+all GPIOs while the command @command{adapter gpio gpio_name} prints the current
+configuration for gpio_name. Not all adapters support this generic GPIO mapping,
+some require their own commands to define the GPIOs used. Adapters that support
+the generic mapping may not support all of the listed options.
+@end deffn
 
 @deffn {Command} {adapter name}
 Returns the name of the debug adapter driver being used.
index 519505dc32466fd68b538fc79b4e9dea79fddaab..76a2aaba60eda0193e9fb9cbd7c4114580be0459 100644 (file)
@@ -48,13 +48,74 @@ static struct {
        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) {
+               adapter_config.gpios[i].gpio_num = -1;
+               adapter_config.gpios[i].chip_num = -1;
+               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.
@@ -71,6 +132,8 @@ int adapter_init(struct command_context *cmd_ctx)
                return ERROR_JTAG_INVALID_INTERFACE;
        }
 
+       adapter_driver_gpios_init();
+
        int retval;
 
        if (adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) {
@@ -540,6 +603,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();
 
@@ -770,6 +835,218 @@ 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;
+}
+
+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 = "";
+
+       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 %d, chip %d, active-%s%s%s%s",
+               gpio_map[gpio_idx].name, dir, gpio_config->gpio_num, 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])) {
+                       int gpio_num; /* Use a meaningful output parameter for more helpful error messages */
+                       COMMAND_PARSE_NUMBER(int, CMD_ARGV[i], gpio_num);
+                       gpio_config->gpio_num = 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]);
+                       int chip_num; /* Use a meaningful output parameter for more helpful error messages */
+                       COMMAND_PARSE_NUMBER(int, CMD_ARGV[i + 1], chip_num);
+                       gpio_config->chip_num = 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)
 {
@@ -887,6 +1164,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
 };
 
@@ -923,3 +1213,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;
+}
index 300769c22965023bfd1164d710128c3057c7f693..625a0b269aa3fb49cea5bcddb661d248cf3f5b2e 100644 (file)
 #include <stddef.h>
 #include <stdint.h>
 
+/** Supported output drive modes for adaptor GPIO */
+enum adapter_gpio_drive_mode {
+       ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL,
+       ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN,
+       ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE,
+};
+
+/** Supported GPIO directions */
+enum adapter_gpio_direction {
+       ADAPTER_GPIO_DIRECTION_INPUT,
+       ADAPTER_GPIO_DIRECTION_OUTPUT,
+       ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL,
+};
+
+/** Supported initial states for GPIO */
+enum adapter_gpio_init_state {
+       ADAPTER_GPIO_INIT_STATE_INACTIVE, /* Should be zero so it is the default state */
+       ADAPTER_GPIO_INIT_STATE_ACTIVE,
+       ADAPTER_GPIO_INIT_STATE_INPUT,
+};
+
+/** Supported pull directions for GPIO */
+enum adapter_gpio_pull {
+       ADAPTER_GPIO_PULL_NONE,
+       ADAPTER_GPIO_PULL_UP,
+       ADAPTER_GPIO_PULL_DOWN,
+};
+
+/** Adapter GPIO */
+enum adapter_gpio_config_index {
+       ADAPTER_GPIO_IDX_TDO,
+       ADAPTER_GPIO_IDX_TDI,
+       ADAPTER_GPIO_IDX_TMS,
+       ADAPTER_GPIO_IDX_TCK,
+       ADAPTER_GPIO_IDX_TRST,
+       ADAPTER_GPIO_IDX_SWDIO,
+       ADAPTER_GPIO_IDX_SWDIO_DIR,
+       ADAPTER_GPIO_IDX_SWCLK,
+       ADAPTER_GPIO_IDX_SRST,
+       ADAPTER_GPIO_IDX_LED,
+       ADAPTER_GPIO_IDX_NUM, /* must be the last item */
+};
+
+/** Configuration options for a single GPIO */
+struct adapter_gpio_config {
+       int gpio_num;
+       int chip_num;
+       enum adapter_gpio_drive_mode drive; /* For outputs only */
+       enum adapter_gpio_init_state init_state;
+       bool active_low;
+       enum adapter_gpio_pull pull;
+};
+
 struct command_context;
 
 /** Register the adapter's commands */
@@ -58,4 +111,14 @@ unsigned int adapter_get_speed_khz(void);
 /** Retrieves the serial number set with command 'adapter serial' */
 const char *adapter_get_required_serial(void);
 
+/**
+ * Retrieves gpio name
+ */
+const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx);
+
+/**
+ * Retrieves gpio configuration set with command 'adapter gpio <signal_name>'
+ */
+const struct adapter_gpio_config *adapter_gpio_get_config(void);
+
 #endif /* OPENOCD_JTAG_ADAPTER_H */
index 238342061fb7f636ba39485750dfdb03947c38a5..8791611e081571ae0f9a588f0a56930097592ccb 100644 (file)
@@ -122,6 +122,66 @@ proc jtag_ntrst_assert_width args {
 #
 # FIXME phase these aids out after some releases
 #
+lappend _telnet_autocomplete_skip adapter_gpio_helper_with_caller
+# Helper for deprecated driver functions that should call "adapter gpio XXX".
+
+# Call this function as:
+#               adapter_gpio_helper_with_caller caller sig_name
+#               adapter_gpio_helper_with_caller caller sig_name gpio_num
+#               adapter_gpio_helper_with_caller caller sig_name chip_num gpio_num
+proc adapter_gpio_helper_with_caller {caller sig_name args} {
+       echo "DEPRECATED! use 'adapter gpio $sig_name' not '$caller'"
+       switch [llength $args] {
+               0 {}
+               1 {eval adapter gpio $sig_name $args}
+               2 {eval adapter gpio $sig_name [lindex $args 1] -chip [lindex $args 0]}
+               default {return -code 1 -level 1 "$caller: syntax error"}
+       }
+       eval adapter gpio $sig_name
+}
+
+lappend _telnet_autocomplete_skip adapter_gpio_helper
+# Call this function as:
+#               adapter_gpio_helper sig_name
+#               adapter_gpio_helper sig_name gpio_num
+#               adapter_gpio_helper sig_name chip_num gpio_num
+proc adapter_gpio_helper {sig_name args} {
+       set caller [lindex [info level -1] 0]
+       eval adapter_gpio_helper_with_caller {"$caller"} $sig_name $args
+}
+
+lappend _telnet_autocomplete_skip adapter_gpio_jtag_nums_with_caller
+# Helper for deprecated driver functions that implemented jtag_nums
+proc adapter_gpio_jtag_nums_with_caller {caller tck_num tms_num tdi_num tdo_num} {
+       echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not '$caller'"
+       eval adapter gpio tck $tck_num
+       eval adapter gpio tms $tms_num
+       eval adapter gpio tdi $tdi_num
+       eval adapter gpio tdo $tdo_num
+}
+
+lappend _telnet_autocomplete_skip adapter_gpio_jtag_nums
+# Helper for deprecated driver functions that implemented jtag_nums
+proc adapter_gpio_jtag_nums {args} {
+       set caller [lindex [info level -1] 0]
+       eval adapter_gpio_jtag_nums_with_caller {"$caller"} $args
+}
+
+lappend _telnet_autocomplete_skip adapter_gpio_swd_nums_with_caller
+# Helper for deprecated driver functions that implemented swd_nums
+proc adapter_gpio_swd_nums_with_caller {caller swclk_num swdio_num} {
+       echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not '$caller'"
+       eval adapter gpio swclk $swclk_num
+       eval adapter gpio swdio $swdio_num
+}
+
+lappend _telnet_autocomplete_skip adapter_gpio_swd_nums
+# Helper for deprecated driver functions that implemented jtag_nums
+proc adapter_gpio_swd_nums {args} {
+       set caller [lindex [info level -1] 0]
+       eval adapter_gpio_swd_nums_with_caller {"$caller"} $args
+}
+
 lappend _telnet_autocomplete_skip jtag_reset
 proc jtag_reset args {
        echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'"

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)