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' 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>
This commit is contained in:
Steve Marple
2022-05-04 22:51:48 +01:00
committed by Antonio Borneo
parent 3adbec9aab
commit 82fd400542
4 changed files with 474 additions and 0 deletions

View 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;
}