openocd: fix SPDX tag format for files .c
[fw/openocd] / src / jtag / drivers / sysfsgpio.c
index f77371c8d9839743c72e5bd3c3d20727667fae19..ee254d66a9854877574f318e03fe056a77494979 100644 (file)
@@ -1,21 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
+
+/* 2014-12: Addition of the SWD protocol support is based on the initial work
+ * on bcm2835gpio.c by Paul Fertser and modifications by Jean-Christian de Rivaz. */
+
 /**
  * @file
  * This driver implements a bitbang jtag interface using gpio lines via
@@ -27,7 +18,7 @@
  *
  * A gpio is required for tck, tms, tdi and tdo. One or both of srst and trst
  * must be also be specified. The required jtag gpios are specified via the
- * sysfsgpio_jtag_nums command or the relevant sysfsgpio_XXX_num commang.
+ * sysfsgpio_jtag_nums command or the relevant sysfsgpio_XXX_num commands.
  * The srst and trst gpios are set via the sysfsgpio_srst_num and
  * sysfsgpio_trst_num respectively. GPIO numbering follows the kernel
  * convention of starting from 0.
 #include "config.h"
 #endif
 
+#include <helper/time_support.h>
 #include <jtag/interface.h>
+#include <transport/transport.h>
 #include "bitbang.h"
 
 /*
  * Helper func to determine if gpio number valid
  *
- * Assume here that there will be less than 1000 gpios on a system
+ * Assume here that there will be less than 10000 gpios on a system
  */
-static int is_gpio_valid(int gpio)
+static bool is_gpio_valid(int gpio)
 {
-       return gpio >= 0 && gpio < 1000;
+       return gpio >= 0 && gpio < 10000;
 }
 
 /*
@@ -87,7 +80,7 @@ static int open_write_close(const char *name, const char *valstr)
  */
 static void unexport_sysfs_gpio(int gpio)
 {
-       char gpiostr[4];
+       char gpiostr[5];
 
        if (!is_gpio_valid(gpio))
                return;
@@ -95,8 +88,6 @@ static void unexport_sysfs_gpio(int gpio)
        snprintf(gpiostr, sizeof(gpiostr), "%d", gpio);
        if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0)
                LOG_ERROR("Couldn't unexport gpio %d", gpio);
-
-       return;
 }
 
 /*
@@ -110,8 +101,9 @@ static void unexport_sysfs_gpio(int gpio)
  */
 static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
 {
+       struct timeval timeout, now;
        char buf[40];
-       char gpiostr[4];
+       char gpiostr[5];
        int ret;
 
        if (!is_gpio_valid(gpio))
@@ -124,32 +116,60 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
                        LOG_WARNING("gpio %d is already exported", gpio);
                } else {
                        LOG_ERROR("Couldn't export gpio %d", gpio);
-                       perror("sysfsgpio: ");
+                       LOG_ERROR("sysfsgpio: %s", strerror(errno));
                        return ERROR_FAIL;
                }
        }
 
+       gettimeofday(&timeout, NULL);
+       timeval_add_time(&timeout, 0, 500000);
+
        snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio);
-       ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
+       for (;;) {
+               ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
+               if (ret >= 0 || errno != EACCES)
+                       break;
+               gettimeofday(&now, NULL);
+               if (timeval_compare(&now, &timeout) >= 0)
+                       break;
+               jtag_sleep(10000);
+       }
        if (ret < 0) {
                LOG_ERROR("Couldn't set direction for gpio %d", gpio);
-               perror("sysfsgpio: ");
+               LOG_ERROR("sysfsgpio: %s", strerror(errno));
                unexport_sysfs_gpio(gpio);
                return ERROR_FAIL;
        }
 
        snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
-       if (is_output)
-               ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC);
-       else
-               ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC);
-
-       if (ret < 0)
+       for (;;) {
+               ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
+               if (ret >= 0 || errno != EACCES)
+                       break;
+               gettimeofday(&now, NULL);
+               if (timeval_compare(&now, &timeout) >= 0)
+                       break;
+               jtag_sleep(10000);
+       }
+       if (ret < 0) {
+               LOG_ERROR("Couldn't open value for gpio %d", gpio);
+               LOG_ERROR("sysfsgpio: %s", strerror(errno));
                unexport_sysfs_gpio(gpio);
+       }
 
        return ret;
 }
 
+/* gpio numbers for each gpio. Negative values are invalid */
+static int tck_gpio = -1;
+static int tms_gpio = -1;
+static int tdi_gpio = -1;
+static int tdo_gpio = -1;
+static int trst_gpio = -1;
+static int srst_gpio = -1;
+static int swclk_gpio = -1;
+static int swdio_gpio = -1;
+
 /*
  * file descriptors for /sys/class/gpio/gpioXX/value
  * Set up during init.
@@ -160,6 +180,74 @@ static int tdi_fd = -1;
 static int tdo_fd = -1;
 static int trst_fd = -1;
 static int srst_fd = -1;
+static int swclk_fd = -1;
+static int swdio_fd = -1;
+
+static int last_swclk;
+static int last_swdio;
+static bool last_stored;
+static bool swdio_input;
+
+static void sysfsgpio_swdio_drive(bool is_output)
+{
+       char buf[40];
+       int ret;
+
+       snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", swdio_gpio);
+       ret = open_write_close(buf, is_output ? "high" : "in");
+       if (ret < 0) {
+               LOG_ERROR("Couldn't set direction for gpio %d", swdio_gpio);
+               LOG_ERROR("sysfsgpio: %s", strerror(errno));
+       }
+
+       last_stored = false;
+       swdio_input = !is_output;
+}
+
+static int sysfsgpio_swdio_read(void)
+{
+       char buf[1];
+
+       /* important to seek to signal sysfs of new read */
+       lseek(swdio_fd, 0, SEEK_SET);
+       int ret = read(swdio_fd, &buf, sizeof(buf));
+
+       if (ret < 0) {
+               LOG_WARNING("reading swdio failed");
+               return 0;
+       }
+
+       return buf[0] != '0';
+}
+
+static int sysfsgpio_swd_write(int swclk, int swdio)
+{
+       const char one[] = "1";
+       const char zero[] = "0";
+
+       size_t bytes_written;
+
+       if (!swdio_input) {
+               if (!last_stored || (swdio != last_swdio)) {
+                       bytes_written = write(swdio_fd, swdio ? &one : &zero, 1);
+                       if (bytes_written != 1)
+                               LOG_WARNING("writing swdio failed");
+               }
+       }
+
+       /* write swclk last */
+       if (!last_stored || (swclk != last_swclk)) {
+               bytes_written = write(swclk_fd, swclk ? &one : &zero, 1);
+               if (bytes_written != 1)
+                       LOG_WARNING("writing swclk failed");
+       }
+
+       last_swdio = swdio;
+       last_swclk = swclk;
+       last_stored = true;
+
+       return ERROR_OK;
+}
 
 /*
  * Bitbang interface read of TDO
@@ -167,7 +255,7 @@ static int srst_fd = -1;
  * The sysfs value will read back either '0' or '1'. The trick here is to call
  * lseek to bypass buffering in the sysfs kernel driver.
  */
-static int sysfsgpio_read(void)
+static bb_value_t sysfsgpio_read(void)
 {
        char buf[1];
 
@@ -180,7 +268,7 @@ static int sysfsgpio_read(void)
                return 0;
        }
 
-       return buf[0] == '1';
+       return buf[0] == '0' ? BB_LOW : BB_HIGH;
 }
 
 /*
@@ -189,7 +277,7 @@ static int sysfsgpio_read(void)
  * Seeing as this is the only function where the outputs are changed,
  * we can cache the old value to avoid needlessly writing it.
  */
-static void sysfsgpio_write(int tck, int tms, int tdi)
+static int sysfsgpio_write(int tck, int tms, int tdi)
 {
        const char one[] = "1";
        const char zero[] = "0";
@@ -230,6 +318,8 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
        last_tdi = tdi;
        last_tms = tms;
        last_tck = tck;
+
+       return ERROR_OK;
 }
 
 /*
@@ -237,8 +327,9 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
  *
  * (1) assert or (0) deassert reset lines
  */
-static void sysfsgpio_reset(int trst, int srst)
+static int sysfsgpio_reset(int trst, int srst)
 {
+       LOG_DEBUG("sysfsgpio_reset");
        const char one[] = "1";
        const char zero[] = "0";
        size_t bytes_written;
@@ -256,15 +347,9 @@ static void sysfsgpio_reset(int trst, int srst)
                if (bytes_written != 1)
                        LOG_WARNING("writing trst failed");
        }
-}
 
-/* gpio numbers for each gpio. Negative values are invalid */
-static int tck_gpio = -1;
-static int tms_gpio = -1;
-static int tdi_gpio = -1;
-static int tdo_gpio = -1;
-static int trst_gpio = -1;
-static int srst_gpio = -1;
+       return ERROR_OK;
+}
 
 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
 {
@@ -277,8 +362,8 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       command_print(CMD_CTX,
-                       "SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdi = %d",
+       command_print(CMD,
+                       "SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d",
                        tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
 
        return ERROR_OK;
@@ -289,7 +374,7 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tck)
        if (CMD_ARGC == 1)
                COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
 
-       command_print(CMD_CTX, "SysfsGPIO num: tck = %d", tck_gpio);
+       command_print(CMD, "SysfsGPIO num: tck = %d", tck_gpio);
        return ERROR_OK;
 }
 
@@ -298,7 +383,7 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tms)
        if (CMD_ARGC == 1)
                COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
 
-       command_print(CMD_CTX, "SysfsGPIO num: tms = %d", tms_gpio);
+       command_print(CMD, "SysfsGPIO num: tms = %d", tms_gpio);
        return ERROR_OK;
 }
 
@@ -307,7 +392,7 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdo)
        if (CMD_ARGC == 1)
                COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
 
-       command_print(CMD_CTX, "SysfsGPIO num: tdo = %d", tdo_gpio);
+       command_print(CMD, "SysfsGPIO num: tdo = %d", tdo_gpio);
        return ERROR_OK;
 }
 
@@ -316,7 +401,7 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdi)
        if (CMD_ARGC == 1)
                COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
 
-       command_print(CMD_CTX, "SysfsGPIO num: tdi = %d", tdi_gpio);
+       command_print(CMD, "SysfsGPIO num: tdi = %d", tdi_gpio);
        return ERROR_OK;
 }
 
@@ -325,7 +410,7 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_srst)
        if (CMD_ARGC == 1)
                COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
 
-       command_print(CMD_CTX, "SysfsGPIO num: srst = %d", srst_gpio);
+       command_print(CMD, "SysfsGPIO num: srst = %d", srst_gpio);
        return ERROR_OK;
 }
 
@@ -334,53 +419,125 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst)
        if (CMD_ARGC == 1)
                COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
 
-       command_print(CMD_CTX, "SysfsGPIO num: trst = %d", trst_gpio);
+       command_print(CMD, "SysfsGPIO num: trst = %d", trst_gpio);
        return ERROR_OK;
 }
 
-static const struct command_registration sysfsgpio_command_handlers[] = {
+COMMAND_HANDLER(sysfsgpio_handle_swd_gpionums)
+{
+       if (CMD_ARGC == 2) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
+       } else if (CMD_ARGC != 0) {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       command_print(CMD,
+                       "SysfsGPIO nums: swclk = %d, swdio = %d",
+                       swclk_gpio, swdio_gpio);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swclk)
+{
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
+
+       command_print(CMD, "SysfsGPIO num: swclk = %d", swclk_gpio);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swdio)
+{
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
+
+       command_print(CMD, "SysfsGPIO num: swdio = %d", swdio_gpio);
+       return ERROR_OK;
+}
+
+static const struct command_registration sysfsgpio_subcommand_handlers[] = {
        {
-               .name = "sysfsgpio_jtag_nums",
+               .name = "jtag_nums",
                .handler = &sysfsgpio_handle_jtag_gpionums,
                .mode = COMMAND_CONFIG,
                .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
-               .usage = "(tck tms tdi tdo)* ",
+               .usage = "[tck tms tdi tdo]",
        },
        {
-               .name = "sysfsgpio_tck_num",
+               .name = "tck_num",
                .handler = &sysfsgpio_handle_jtag_gpionum_tck,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tck.",
+               .usage = "[tck]",
        },
        {
-               .name = "sysfsgpio_tms_num",
+               .name = "tms_num",
                .handler = &sysfsgpio_handle_jtag_gpionum_tms,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tms.",
+               .usage = "[tms]",
        },
        {
-               .name = "sysfsgpio_tdo_num",
+               .name = "tdo_num",
                .handler = &sysfsgpio_handle_jtag_gpionum_tdo,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tdo.",
+               .usage = "[tdo]",
        },
        {
-               .name = "sysfsgpio_tdi_num",
+               .name = "tdi_num",
                .handler = &sysfsgpio_handle_jtag_gpionum_tdi,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for tdi.",
+               .usage = "[tdi]",
        },
        {
-               .name = "sysfsgpio_srst_num",
+               .name = "srst_num",
                .handler = &sysfsgpio_handle_jtag_gpionum_srst,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for srst.",
+               .usage = "[srst]",
        },
        {
-               .name = "sysfsgpio_trst_num",
+               .name = "trst_num",
                .handler = &sysfsgpio_handle_jtag_gpionum_trst,
                .mode = COMMAND_CONFIG,
                .help = "gpio number for trst.",
+               .usage = "[trst]",
+       },
+       {
+               .name = "swd_nums",
+               .handler = &sysfsgpio_handle_swd_gpionums,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio numbers for swclk, swdio. (in that order)",
+               .usage = "[swclk swdio]",
+       },
+       {
+               .name = "swclk_num",
+               .handler = &sysfsgpio_handle_swd_gpionum_swclk,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for swclk.",
+               .usage = "[swclk]",
+       },
+       {
+               .name = "swdio_num",
+               .handler = &sysfsgpio_handle_swd_gpionum_swdio,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for swdio.",
+               .usage = "[swdio]",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration sysfsgpio_command_handlers[] = {
+       {
+               .name = "sysfsgpio",
+               .mode = COMMAND_ANY,
+               .help = "perform sysfsgpio management",
+               .chain = sysfsgpio_subcommand_handlers,
+               .usage = "",
        },
        COMMAND_REGISTRATION_DONE
 };
@@ -388,20 +545,32 @@ static const struct command_registration sysfsgpio_command_handlers[] = {
 static int sysfsgpio_init(void);
 static int sysfsgpio_quit(void);
 
-struct jtag_interface sysfsgpio_interface = {
-       .name = "sysfsgpio",
+static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL };
+
+static struct jtag_interface sysfsgpio_interface = {
        .supported = DEBUG_CAP_TMS_SEQ,
        .execute_queue = bitbang_execute_queue,
-       .transports = jtag_only,
+};
+
+struct adapter_driver sysfsgpio_adapter_driver = {
+       .name = "sysfsgpio",
+       .transports = sysfsgpio_transports,
        .commands = sysfsgpio_command_handlers,
+
        .init = sysfsgpio_init,
        .quit = sysfsgpio_quit,
+       .reset = sysfsgpio_reset,
+
+       .jtag_ops = &sysfsgpio_interface,
+       .swd_ops = &bitbang_swd,
 };
 
 static struct bitbang_interface sysfsgpio_bitbang = {
        .read = sysfsgpio_read,
        .write = sysfsgpio_write,
-       .reset = sysfsgpio_reset,
+       .swdio_read = sysfsgpio_swdio_read,
+       .swdio_drive = sysfsgpio_swdio_drive,
+       .swd_write = sysfsgpio_swd_write,
        .blink = 0
 };
 
@@ -418,71 +587,101 @@ static void cleanup_fd(int fd, int gpio)
 
 static void cleanup_all_fds(void)
 {
-       cleanup_fd(tck_fd, tck_gpio);
-       cleanup_fd(tms_fd, tms_gpio);
-       cleanup_fd(tdi_fd, tdi_gpio);
-       cleanup_fd(tdo_fd, tdo_gpio);
-       cleanup_fd(trst_fd, trst_gpio);
+       if (transport_is_jtag()) {
+               cleanup_fd(tck_fd, tck_gpio);
+               cleanup_fd(tms_fd, tms_gpio);
+               cleanup_fd(tdi_fd, tdi_gpio);
+               cleanup_fd(tdo_fd, tdo_gpio);
+               cleanup_fd(trst_fd, trst_gpio);
+       }
+       if (transport_is_swd()) {
+               cleanup_fd(swclk_fd, swclk_gpio);
+               cleanup_fd(swdio_fd, swdio_gpio);
+       }
        cleanup_fd(srst_fd, srst_gpio);
 }
 
+static bool sysfsgpio_jtag_mode_possible(void)
+{
+       if (!is_gpio_valid(tck_gpio))
+               return false;
+       if (!is_gpio_valid(tms_gpio))
+               return false;
+       if (!is_gpio_valid(tdi_gpio))
+               return false;
+       if (!is_gpio_valid(tdo_gpio))
+               return false;
+       return true;
+}
+
+static bool sysfsgpio_swd_mode_possible(void)
+{
+       if (!is_gpio_valid(swclk_gpio))
+               return false;
+       if (!is_gpio_valid(swdio_gpio))
+               return false;
+       return true;
+}
+
 static int sysfsgpio_init(void)
 {
        bitbang_interface = &sysfsgpio_bitbang;
 
-       LOG_INFO("SysfsGPIO JTAG bitbang driver");
-
-       if (!(is_gpio_valid(tck_gpio)
-                       && is_gpio_valid(tms_gpio)
-                       && is_gpio_valid(tdi_gpio)
-                       && is_gpio_valid(tdo_gpio))) {
-               if (!is_gpio_valid(tck_gpio))
-                       LOG_ERROR("gpio num for tck is invalid");
-               if (!is_gpio_valid(tms_gpio))
-                       LOG_ERROR("gpio num for tms is invalid");
-               if (!is_gpio_valid(tdo_gpio))
-                       LOG_ERROR("gpio num for tdo is invalid");
-               if (!is_gpio_valid(tdi_gpio))
-                       LOG_ERROR("gpio num for tdi is invalid");
-
-               LOG_ERROR("Require tck, tms, tdi and tdo gpios to all be specified");
-               return ERROR_JTAG_INIT_FAILED;
-       }
-
-       if (!is_gpio_valid(trst_gpio) && !is_gpio_valid(srst_gpio)) {
-               LOG_ERROR("Require at least one of trst or srst gpios to be specified");
-               return ERROR_JTAG_INIT_FAILED;
-       }
+       LOG_INFO("SysfsGPIO JTAG/SWD bitbang driver");
 
        /*
         * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
         * as outputs.  Drive TDI and TCK low, and TMS/TRST/SRST high.
+        * For SWD, SWCLK and SWDIO are configures as output high.
         */
-       tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0);
-       if (tck_fd < 0)
-               goto out_error;
 
-       tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1);
-       if (tms_fd < 0)
-               goto out_error;
+       if (transport_is_jtag()) {
+               if (!sysfsgpio_jtag_mode_possible()) {
+                       LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
+                       return ERROR_JTAG_INIT_FAILED;
+               }
 
-       tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0);
-       if (tdi_fd < 0)
-               goto out_error;
+               tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0);
+               if (tck_fd < 0)
+                       goto out_error;
 
-       tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0);
-       if (tdo_fd < 0)
-               goto out_error;
+               tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1);
+               if (tms_fd < 0)
+                       goto out_error;
 
-       /* assume active low*/
-       if (trst_gpio > 0) {
-               trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1);
-               if (trst_fd < 0)
+               tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0);
+               if (tdi_fd < 0)
+                       goto out_error;
+
+               tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0);
+               if (tdo_fd < 0)
+                       goto out_error;
+
+               /* assume active low*/
+               if (trst_gpio >= 0) {
+                       trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1);
+                       if (trst_fd < 0)
+                               goto out_error;
+               }
+       }
+
+       if (transport_is_swd()) {
+               if (!sysfsgpio_swd_mode_possible()) {
+                       LOG_ERROR("Require swclk and swdio gpio for SWD mode");
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+
+               swclk_fd = setup_sysfs_gpio(swclk_gpio, 1, 0);
+               if (swclk_fd < 0)
+                       goto out_error;
+
+               swdio_fd = setup_sysfs_gpio(swdio_gpio, 1, 0);
+               if (swdio_fd < 0)
                        goto out_error;
        }
 
        /* assume active low*/
-       if (srst_gpio > 0) {
+       if (srst_gpio >= 0) {
                srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1);
                if (srst_fd < 0)
                        goto out_error;
@@ -500,4 +699,3 @@ static int sysfsgpio_quit(void)
        cleanup_all_fds();
        return ERROR_OK;
 }
-