linuxgpiod: add SWDIO buffer
authorSteve Marple <stevemarple@googlemail.com>
Tue, 12 Apr 2022 17:25:40 +0000 (18:25 +0100)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 30 Apr 2022 17:47:38 +0000 (17:47 +0000)
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 <stevemarple@googlemail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6936
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
src/jtag/drivers/linuxgpiod.c

index 9f9f27a9f24102777d079c176f96c1ec4a9843f4..288035f2e077edb885b0bd1a4f075c730e3c010a 100644 (file)
@@ -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,