From 20adf85f3484ee7137f2c11a491a6929b342d1f5 Mon Sep 17 00:00:00 2001 From: Steve Marple Date: Tue, 12 Apr 2022 18:25:40 +0100 Subject: [PATCH] linuxgpiod: add SWDIO buffer The SWDIO buffer requires a direction pin to select input or output direction. Output is selected by a high logic level (matches bcm2835gpio driver). Change-Id: I240cb99a5dfea08121bb33d4b5e2108ce7597468 Signed-off-by: Steve Marple Reviewed-on: https://review.openocd.org/c/openocd/+/6936 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/linuxgpiod.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 9f9f27a9f2..288035f2e0 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -27,6 +27,7 @@ static int trst_gpio = -1; static int srst_gpio = -1; static int swclk_gpio = -1; static int swdio_gpio = -1; +static int swdio_dir_gpio = -1; static int led_gpio = -1; static int gpiochip = -1; static int tck_gpiochip = -1; @@ -37,6 +38,7 @@ static int trst_gpiochip = -1; static int srst_gpiochip = -1; static int swclk_gpiochip = -1; static int swdio_gpiochip = -1; +static int swdio_dir_gpiochip = -1; static int led_gpiochip = -1; static struct gpiod_chip *gpiod_chip_tck; @@ -47,6 +49,7 @@ static struct gpiod_chip *gpiod_chip_trst; static struct gpiod_chip *gpiod_chip_srst; static struct gpiod_chip *gpiod_chip_swclk; static struct gpiod_chip *gpiod_chip_swdio; +static struct gpiod_chip *gpiod_chip_swdio_dir; static struct gpiod_chip *gpiod_chip_led; static struct gpiod_line *gpiod_tck; @@ -56,6 +59,7 @@ static struct gpiod_line *gpiod_tdo; static struct gpiod_line *gpiod_trst; static struct gpiod_line *gpiod_swclk; static struct gpiod_line *gpiod_swdio; +static struct gpiod_line *gpiod_swdio_dir; static struct gpiod_line *gpiod_srst; static struct gpiod_line *gpiod_led; @@ -63,6 +67,7 @@ static int last_swclk; static int last_swdio; static bool last_stored; static bool swdio_input; +static bool swdio_dir_is_active_high = true; /* Bitbang interface read of TDO */ static bb_value_t linuxgpiod_read(void) @@ -152,6 +157,11 @@ static void linuxgpiod_swdio_drive(bool is_output) gpiod_line_release(gpiod_swdio); if (is_output) { + if (gpiod_swdio_dir) { + retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 1 : 0); + if (retval < 0) + LOG_WARNING("Fail set swdio_dir"); + } retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1); if (retval < 0) LOG_WARNING("Fail request_output line swdio"); @@ -159,6 +169,11 @@ static void linuxgpiod_swdio_drive(bool is_output) retval = gpiod_line_request_input(gpiod_swdio, "OpenOCD"); if (retval < 0) LOG_WARNING("Fail request_input line swdio"); + if (gpiod_swdio_dir) { + retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 0 : 1); + if (retval < 0) + LOG_WARNING("Fail set swdio_dir"); + } } last_stored = false; @@ -297,6 +312,8 @@ static int linuxgpiod_quit(void) gpiod_chip_close(gpiod_chip_srst); if (gpiod_chip_swdio != NULL) gpiod_chip_close(gpiod_chip_swdio); + if (gpiod_chip_swdio_dir != NULL) + gpiod_chip_close(gpiod_chip_swdio_dir); if (gpiod_chip_swclk != NULL) gpiod_chip_close(gpiod_chip_swclk); if (gpiod_chip_trst != NULL) @@ -451,10 +468,26 @@ static int linuxgpiod_init(void) goto out_error; } + if (is_gpio_valid(swdio_dir_gpio)) { + gpiod_chip_swdio_dir = gpiod_chip_open_by_number(swdio_dir_gpiochip); + if (!gpiod_chip_swdio_dir) { + LOG_ERROR("Cannot open LinuxGPIOD swdio_dir_gpiochip %d", swdio_dir_gpiochip); + goto out_error; + } + } + gpiod_swclk = helper_get_output_line("swclk", gpiod_chip_swclk, swclk_gpio, 1); if (!gpiod_swclk) goto out_error; + /* Set buffer direction before making SWDIO an output */ + if (is_gpio_valid(swdio_dir_gpio)) { + gpiod_swdio_dir = helper_get_output_line("swdio_dir", gpiod_chip_swdio_dir, swdio_dir_gpio, + swdio_dir_is_active_high ? 1 : 0); + if (!gpiod_swdio_dir) + goto out_error; + } + gpiod_swdio = helper_get_output_line("swdio", gpiod_chip_swdio, swdio_gpio, 1); if (!gpiod_swdio) goto out_error; @@ -593,6 +626,12 @@ COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio) &swdio_gpio); } +COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio_dir) +{ + return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swdio_dir", &swdio_dir_gpiochip, + &swdio_dir_gpio); +} + COMMAND_HANDLER(linuxgpiod_handle_gpionum_led) { return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "led", &led_gpiochip, @@ -611,6 +650,7 @@ COMMAND_HANDLER(linuxgpiod_handle_gpiochip) srst_gpiochip = gpiochip; swclk_gpiochip = gpiochip; swdio_gpiochip = gpiochip; + swdio_dir_gpiochip = gpiochip; led_gpiochip = gpiochip; } @@ -689,6 +729,13 @@ static const struct command_registration linuxgpiod_subcommand_handlers[] = { .help = "gpio chip number (optional) and gpio number for swdio.", .usage = "[chip] swdio", }, + { + .name = "swdio_dir_num", + .handler = linuxgpiod_handle_swd_gpionum_swdio_dir, + .mode = COMMAND_CONFIG, + .help = "gpio chip number (optional) and gpio number for swdio_dir.", + .usage = "[chip] swdio_dir", + }, { .name = "led_num", .handler = linuxgpiod_handle_gpionum_led, -- 2.30.2