aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJean-Christian de Rivaz <jc@eclis.ch>2014-12-11 17:50:33 +0100
committerPaul Fertser <fercerpav@gmail.com>2015-02-22 16:21:15 +0000
commite290cb76c8d5abfe3929dc9436b936708684d989 (patch)
treef2638b933647061b460fcad48b5502b6a6a26c17 /src
parente971c7f4238030a362d3f17c4e519b402b3166cd (diff)
Add SWD protocol support to sysfsgpio
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>
Diffstat (limited to 'src')
-rw-r--r--src/jtag/drivers/sysfsgpio.c278
1 files changed, 229 insertions, 49 deletions
diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c
index dfb4dcb3..d822562a 100644
--- a/src/jtag/drivers/sysfsgpio.c
+++ b/src/jtag/drivers/sysfsgpio.c
@@ -16,6 +16,10 @@
* 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
@@ -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);
- 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);
+ }
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 +173,72 @@ 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);
+ 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
@@ -191,6 +270,11 @@ static int sysfsgpio_read(void)
*/
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";
@@ -239,6 +323,7 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
*/
static void sysfsgpio_reset(int trst, int srst)
{
+ LOG_DEBUG("sysfsgpio_reset");
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) {
@@ -338,6 +415,40 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst)
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",
@@ -382,17 +493,39 @@ static const struct command_registration sysfsgpio_command_handlers[] = {
.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);
+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,
- .transports = jtag_only,
+ .transports = sysfsgpio_transports,
+ .swd = &bitbang_swd,
.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,
+ .swdio_read = sysfsgpio_swdio_read,
+ .swdio_drive = sysfsgpio_swdio_drive,
.blink = 0
};
@@ -426,68 +561,113 @@ static void cleanup_all_fds(void)
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;
- 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;
}
+
/*
* 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*/
- 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*/
- if (srst_gpio > 0) {
+ if (srst_gpio >= 0) {
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: