This is an automated email from Gerrit. "Steve Marple <stevemar...@googlemail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6967
-- gerrit commit cff4398e51b1bfa469ada7f7c0f48dfba447277b Author: Steve Marple <stevemar...@googlemail.com> Date: Wed May 4 22:51:48 2022 +0100 jtag/adapter: add command 'adapter gpio' 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' to be proposed as replacement of the driver-specific ones. Change-Id: I1ca9ca94f0c7df5713172e9f62ffb0ad64e9ee97 Signed-off-by: Steve Marple <stevemar...@googlemail.com> diff --git a/src/helper/command.c b/src/helper/command.c index 1e769d7190..be7de854d9 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1370,7 +1370,7 @@ DEFINE_PARSE_LONGLONG(_s32, int32_t, n < INT32_MIN, INT32_MAX) DEFINE_PARSE_LONGLONG(_s16, int16_t, n < INT16_MIN, INT16_MAX) DEFINE_PARSE_LONGLONG(_s8, int8_t, n < INT8_MIN, INT8_MAX) -static int command_parse_bool(const char *in, bool *out, +int command_parse_bool(const char *in, bool *out, const char *on, const char *off) { if (strcasecmp(in, on) == 0) diff --git a/src/helper/command.h b/src/helper/command.h index 796cd9d3b3..b7c28f0ad5 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -508,6 +508,8 @@ DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); out = value; \ } while (0) +int command_parse_bool(const char *in, bool *out, + const char *on, const char *off); int command_parse_bool_arg(const char *in, bool *out); COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 14452d42f2..9dcb13e0cd 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -36,6 +36,22 @@ enum adapter_clk_mode { CLOCK_MODE_RCLK }; +/* TODO: Set sane inital values for GPIO. Most should be something similar to this: +const struct adapter_gpio_config push_pull_gpio = { + .gpio_num = -1, + .chip_num = -1, + .drive = DRIVE_MODE_PUSH_PULL, + .active_high = true, + .init_active = false, +}; +*/ + +/** All GPIOs which can be configured with the "adapter gpio" command */ +struct adaptor_gpio { + struct adapter_gpio_config tdo; + struct adapter_gpio_config led; +}; + /** * Adapter configuration */ @@ -46,6 +62,7 @@ static struct { enum adapter_clk_mode clock_mode; int speed_khz; int rclk_fallback_speed_khz; + struct adaptor_gpio gpio; } adapter_config; bool is_adapter_initialized(void) @@ -762,6 +779,130 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert) (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); } +static struct adapter_gpio_config *get_gpio_config(const char *signal_name) +{ + if (strcmp(signal_name, "tdo") == 0) + return &adapter_config.gpio.tdo; + if (strcmp(signal_name, "led") == 0) + return &adapter_config.gpio.led; + return NULL; +} + +const struct adapter_gpio_config *adapter_get_gpio_config(const char *signal_name) +{ + return (const struct adapter_gpio_config *)get_gpio_config(signal_name); +} + +COMMAND_HELPER(helper_adapter_gpio_options, bool is_output, unsigned int *i, + struct adapter_gpio_config *gpio_config) +{ + const char *opt = CMD_ARGV[*i]; + if (strcmp(opt, "-chip") == 0) { + if (CMD_ARGC - *i < 2) { + LOG_ERROR("-chip option requires a parameter"); + return ERROR_FAIL; + } else { + 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; + return ERROR_OK; + } + } + + if (strcmp(opt, "-active-high") == 0) { + ++(*i); + gpio_config->active_high = true; + return ERROR_OK; + } + if (strcmp(opt, "-active-low") == 0) { + ++(*i); + gpio_config->active_high = false; + return ERROR_OK; + } + + if (is_output) { + /* Drive */ + if (strcmp(opt, "-push-pull") == 0) { + ++(*i); + gpio_config->drive = DRIVE_MODE_PUSH_PULL; + return ERROR_OK; + } + if (strcmp(opt, "-open-drain") == 0) { + ++(*i); + gpio_config->drive = DRIVE_MODE_OPEN_DRAIN; + return ERROR_OK; + } + if (strcmp(opt, "-open-source") == 0) { + ++(*i); + gpio_config->drive = DRIVE_MODE_OPEN_SOURCE; + return ERROR_OK; + } + + /* Initial state */ + if (strcmp(opt, "-init-state") == 0) { + if (CMD_ARGC - *i < 2) { + LOG_ERROR("-init-state option requires a parameter"); + return ERROR_FAIL; + } + LOG_DEBUG("-init-state arg is %s", CMD_ARGV[*i + 1]); + int retval = command_parse_bool(CMD_ARGV[*i + 1], + &(gpio_config->init_active), "active", "inactive"); + *i += 2; + return retval; + } + } + + LOG_ERROR("unknown option for %s: %s", CMD_NAME, opt); + return ERROR_COMMAND_SYNTAX_ERROR; +} + +COMMAND_HELPER(adapter_gpio_config_handler, bool is_output) +{ + unsigned int i = 0; + struct adapter_gpio_config *gpio_config; + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + gpio_config = get_gpio_config(CMD_NAME); + if (!gpio_config) { + LOG_ERROR("adapter has no gpio named %s", CMD_NAME); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + 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; + } else { + if (*CMD_ARGV[i] == '-') { + int retval = CALL_COMMAND_HANDLER(helper_adapter_gpio_options, is_output, &i, gpio_config); + if (retval != ERROR_OK) + return retval; + } else { + LOG_ERROR("unknown option for %s: %s", CMD_NAME, CMD_ARGV[i]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + } + + return ERROR_OK; +} + +COMMAND_HANDLER(adapter_gpio_input_config_handler) +{ + return CALL_COMMAND_HANDLER(adapter_gpio_config_handler, false); +} + +COMMAND_HANDLER(adapter_gpio_output_config_handler) +{ + return CALL_COMMAND_HANDLER(adapter_gpio_config_handler, true); +} + #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS COMMAND_HANDLER(handle_usb_location_command) { @@ -805,6 +946,30 @@ static const struct command_registration adapter_srst_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration adapter_gpio_name_handlers[] = { + { + .name = "tdo", + .handler = adapter_gpio_input_config_handler, + .mode = COMMAND_CONFIG, + .help = "tdo gpio configuration", + .usage = "[number] " + "[-chip chip_number] " + "[-active-high|-active-low]", + }, + { + .name = "led", + .handler = adapter_gpio_output_config_handler, + .mode = COMMAND_CONFIG, + .help = "led gpio configuration", + .usage = "[number] " + "[-chip chip_number] " + "[-active-high|-active-low] " + "[-push-pull|-open-drain|-open-source] " + "[-init-state active|inactive]", + }, + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration adapter_command_handlers[] = { { .name = "driver", @@ -879,6 +1044,13 @@ static const struct command_registration adapter_command_handlers[] = { .help = "Controls SRST and TRST lines.", .usage = "|assert [srst|trst [deassert|assert srst|trst]]", }, + { + .name = "gpio", + .mode = COMMAND_CONFIG, + .help = "gpio adapter command group", + .usage = "", + .chain = adapter_gpio_name_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/adapter.h b/src/jtag/adapter.h index 300769c229..30930f4bb3 100644 --- a/src/jtag/adapter.h +++ b/src/jtag/adapter.h @@ -11,6 +11,22 @@ #include <stddef.h> #include <stdint.h> +/** Supported output drive modes for adaptor GPIO */ +enum adapter_gpio_drive_mode { + DRIVE_MODE_PUSH_PULL, + DRIVE_MODE_OPEN_DRAIN, + DRIVE_MODE_OPEN_SOURCE, +}; + +/** 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 */ + bool active_high; + bool init_active; +}; + struct command_context; /** Register the adapter's commands */ @@ -58,4 +74,9 @@ 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 configuration set with command 'adapter gpio <signal_name>' + */ +const struct adapter_gpio_config *adapter_get_gpio_config(const char *signal_name); + #endif /* OPENOCD_JTAG_ADAPTER_H */ --