Add SWD protocol support to sysfsgpio 38/2438/6
authorJean-Christian de Rivaz <jc@eclis.ch>
Thu, 11 Dec 2014 16:50:33 +0000 (17:50 +0100)
committerPaul Fertser <fercerpav@gmail.com>
Sun, 22 Feb 2015 16:21:15 +0000 (16:21 +0000)
Based on the initial work on bcm2835gpio.c by Paul Fertser with many
additions. Modifications to the GPIO handling was minimal in this
patch. A more big modification is required before cleanup the
interface between bitbang and sysfsgpio.

Change-Id: I54bf2a2aa2ca059368b0e0e105dff6084b73d624
Signed-off-by: Jean-Christian de Rivaz <jc@eclis.ch>
Reviewed-on: http://openocd.zylin.com/2438
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
src/jtag/drivers/sysfsgpio.c

index dfb4dcb3cff3ab242e47678dcfc7b5afbb97f9b6..d822562a5e5953d2af3ba8999d367d2b4648f515 100644 (file)
  *   Free Software Foundation, Inc.,                                       *
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
  *   Free Software Foundation, Inc.,                                       *
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
 /**
  * @file
  * This driver implements a bitbang jtag interface using gpio lines via
@@ -139,17 +143,26 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
        }
 
        snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
        }
 
        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)
+       ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
+       if (ret < 0) {
+               LOG_ERROR("Couldn't open value for gpio %d", gpio);
+               perror("sysfsgpio: ");
                unexport_sysfs_gpio(gpio);
                unexport_sysfs_gpio(gpio);
+       }
 
        return ret;
 }
 
 
        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.
 /*
  * file descriptors for /sys/class/gpio/gpioXX/value
  * Set up during init.
@@ -160,6 +173,72 @@ static int tdi_fd = -1;
 static int tdo_fd = -1;
 static int trst_fd = -1;
 static int srst_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);
+               perror("sysfsgpio: ");
+       }
+
+       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] == '1';
+}
+
+static void sysfsgpio_swdio_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;
+}
 
 /*
  * Bitbang interface read of TDO
 
 /*
  * Bitbang interface read of TDO
@@ -191,6 +270,11 @@ static int sysfsgpio_read(void)
  */
 static void sysfsgpio_write(int tck, int tms, int tdi)
 {
  */
 static void sysfsgpio_write(int tck, int tms, int tdi)
 {
+       if (swd_mode) {
+               sysfsgpio_swdio_write(tck, tdi);
+               return;
+       }
+
        const char one[] = "1";
        const char zero[] = "0";
 
        const char one[] = "1";
        const char zero[] = "0";
 
@@ -239,6 +323,7 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
  */
 static void sysfsgpio_reset(int trst, int srst)
 {
  */
 static void sysfsgpio_reset(int trst, int srst)
 {
+       LOG_DEBUG("sysfsgpio_reset");
        const char one[] = "1";
        const char zero[] = "0";
        size_t bytes_written;
        const char one[] = "1";
        const char zero[] = "0";
        size_t bytes_written;
@@ -258,14 +343,6 @@ static void sysfsgpio_reset(int trst, int srst)
        }
 }
 
        }
 }
 
-/* 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;
-
 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
 {
        if (CMD_ARGC == 4) {
 COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
 {
        if (CMD_ARGC == 4) {
@@ -338,6 +415,40 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst)
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
+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_CTX,
+                       "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_CTX, "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_CTX, "SysfsGPIO num: swdio = %d", swdio_gpio);
+       return ERROR_OK;
+}
+
 static const struct command_registration sysfsgpio_command_handlers[] = {
        {
                .name = "sysfsgpio_jtag_nums",
 static const struct command_registration sysfsgpio_command_handlers[] = {
        {
                .name = "sysfsgpio_jtag_nums",
@@ -382,17 +493,39 @@ static const struct command_registration sysfsgpio_command_handlers[] = {
                .mode = COMMAND_CONFIG,
                .help = "gpio number for trst.",
        },
                .mode = COMMAND_CONFIG,
                .help = "gpio number for trst.",
        },
+       {
+               .name = "sysfsgpio_swd_nums",
+               .handler = &sysfsgpio_handle_swd_gpionums,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio numbers for swclk, swdio. (in that order)",
+               .usage = "(swclk swdio)* ",
+       },
+       {
+               .name = "sysfsgpio_swclk_num",
+               .handler = &sysfsgpio_handle_swd_gpionum_swclk,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for swclk.",
+       },
+       {
+               .name = "sysfsgpio_swdio_num",
+               .handler = &sysfsgpio_handle_swd_gpionum_swdio,
+               .mode = COMMAND_CONFIG,
+               .help = "gpio number for swdio.",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
 static int sysfsgpio_init(void);
 static int sysfsgpio_quit(void);
 
        COMMAND_REGISTRATION_DONE
 };
 
 static int sysfsgpio_init(void);
 static int sysfsgpio_quit(void);
 
+static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL };
+
 struct jtag_interface sysfsgpio_interface = {
        .name = "sysfsgpio",
        .supported = DEBUG_CAP_TMS_SEQ,
        .execute_queue = bitbang_execute_queue,
 struct jtag_interface sysfsgpio_interface = {
        .name = "sysfsgpio",
        .supported = DEBUG_CAP_TMS_SEQ,
        .execute_queue = bitbang_execute_queue,
-       .transports = jtag_only,
+       .transports = sysfsgpio_transports,
+       .swd = &bitbang_swd,
        .commands = sysfsgpio_command_handlers,
        .init = sysfsgpio_init,
        .quit = sysfsgpio_quit,
        .commands = sysfsgpio_command_handlers,
        .init = sysfsgpio_init,
        .quit = sysfsgpio_quit,
@@ -402,6 +535,8 @@ static struct bitbang_interface sysfsgpio_bitbang = {
        .read = sysfsgpio_read,
        .write = sysfsgpio_write,
        .reset = sysfsgpio_reset,
        .read = sysfsgpio_read,
        .write = sysfsgpio_write,
        .reset = sysfsgpio_reset,
+       .swdio_read = sysfsgpio_swdio_read,
+       .swdio_drive = sysfsgpio_swdio_drive,
        .blink = 0
 };
 
        .blink = 0
 };
 
@@ -426,68 +561,113 @@ static void cleanup_all_fds(void)
        cleanup_fd(srst_fd, srst_gpio);
 }
 
        cleanup_fd(srst_fd, srst_gpio);
 }
 
+static bool sysfsgpio_jtag_mode_possible(void)
+{
+       if (!is_gpio_valid(tck_gpio))
+               return 0;
+       if (!is_gpio_valid(tms_gpio))
+               return 0;
+       if (!is_gpio_valid(tdi_gpio))
+               return 0;
+       if (!is_gpio_valid(tdo_gpio))
+               return 0;
+       return 1;
+}
+
+static bool sysfsgpio_swd_mode_possible(void)
+{
+       if (!is_gpio_valid(swclk_gpio))
+               return 0;
+       if (!is_gpio_valid(swdio_gpio))
+               return 0;
+       return 1;
+}
+
 static int sysfsgpio_init(void)
 {
        bitbang_interface = &sysfsgpio_bitbang;
 
 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;
-       }
+       LOG_INFO("SysfsGPIO JTAG/SWD bitbang driver");
 
 
-       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");
+       if (sysfsgpio_jtag_mode_possible()) {
+               if (sysfsgpio_swd_mode_possible())
+                       LOG_INFO("JTAG and SWD modes enabled");
+               else
+                       LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
+               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;
+               }
+       } else if (sysfsgpio_swd_mode_possible()) {
+               LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
+       } else {
+               LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
                return ERROR_JTAG_INIT_FAILED;
        }
 
                return ERROR_JTAG_INIT_FAILED;
        }
 
+
        /*
         * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
         * as outputs.  Drive TDI and TCK low, and TMS/TRST/SRST high.
        /*
         * 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;
+       if (tck_gpio >= 0) {
+               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 (tms_gpio >= 0) {
+               tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1);
+               if (tms_fd < 0)
+                       goto out_error;
+       }
 
 
-       tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0);
-       if (tdi_fd < 0)
-               goto out_error;
+       if (tdi_gpio >= 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;
+       if (tdo_gpio >= 0) {
+               tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0);
+               if (tdo_fd < 0)
+                       goto out_error;
+       }
 
        /* assume active low*/
 
        /* assume active low*/
-       if (trst_gpio > 0) {
+       if (trst_gpio >= 0) {
                trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1);
                if (trst_fd < 0)
                        goto out_error;
        }
 
        /* assume active low*/
                trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1);
                if (trst_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;
        }
 
                srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1);
                if (srst_fd < 0)
                        goto out_error;
        }
 
+       if (swclk_gpio >= 0) {
+               swclk_fd = setup_sysfs_gpio(swclk_gpio, 1, 0);
+               if (swclk_fd < 0)
+                       goto out_error;
+       }
+
+       if (swdio_gpio >= 0) {
+               swdio_fd = setup_sysfs_gpio(swdio_gpio, 1, 0);
+               if (swdio_fd < 0)
+                       goto out_error;
+       }
+
+       if (sysfsgpio_swd_mode_possible()) {
+               if (swd_mode)
+                       bitbang_swd_switch_seq(NULL, JTAG_TO_SWD);
+               else
+                       bitbang_swd_switch_seq(NULL, SWD_TO_JTAG);
+       }
+
        return ERROR_OK;
 
 out_error:
        return ERROR_OK;
 
 out_error:

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)