From: OpenOCD-Gerrit <ope...@us...> - 2020-07-13 23:39:37
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via 6962da00287c88c3fa89df8a8623a956735379db (commit) via aa277fb358b7ff02b8231d4141c673722c580cf3 (commit) via 93be480c908d4751936ed779be1f00998c668c87 (commit) via ee86f3ef92adfe1f41ad67b4b154ee7ea0327cc8 (commit) via a8e483a2bf9d1b4eb16b7a0e0851b455a935fcf0 (commit) from ed17994757661ed7a32cd9ad59aa001e5cd22692 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6962da00287c88c3fa89df8a8623a956735379db Author: Antonio Borneo <bor...@gm...> Date: Thu Apr 2 00:14:21 2020 +0200 tcl/interface: add example of linuxgpiod through dln-2 The USB adapter DLN-2 provides 32 GPIO (beside I2C, SPI, ...). Use the first 6 GPIO for a SWD/JTAG bitbanging example through linuxgpiod driver. Change-Id: I229c2078142ec648fc6430b5d123539045dcfbda Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5561 Tested-by: jenkins diff --git a/tcl/interface/dln-2-gpiod.cfg b/tcl/interface/dln-2-gpiod.cfg new file mode 100644 index 000000000..1859688be --- /dev/null +++ b/tcl/interface/dln-2-gpiod.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Use DLN-2 GPIO through linuxgpiod +# +# +-----------+-------------+-------------+ +# | signal | DLN-2 | gpio offset | +# +-----------+-------------+-------------+ +# | nSRST | J3.1 (PA0) | 0 | +# | TDO | J3.2 (PA1) | 1 | +# | TCK/SWCLK | J3.3 (PA2) | 2 | +# | TMS/SWDIO | J3.4 (PA3) | 3 | +# | TDI | J3.5 (PA4) | 4 | +# | nTRST | J3.6 (PA5) | 5 | +# | GND | J3.12 (GND) | | +# +-----------+-------------+-------------+ + +adapter driver linuxgpiod + +linuxgpiod_gpiochip 0 +linuxgpiod_jtag_nums 2 3 4 1 +linuxgpiod_trst_num 5 +linuxgpiod_swd_nums 2 3 +linuxgpiod_srst_num 0 + +reset_config trst_and_srst separate srst_push_pull commit aa277fb358b7ff02b8231d4141c673722c580cf3 Author: Antonio Borneo <bor...@gm...> Date: Mon Mar 30 21:54:17 2020 +0200 contrib/60-openocd.rules: add udev rules for Linux gpiod Change-Id: I767776d3659adddefe81a63f351794318463fd50 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5560 Tested-by: jenkins diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 617346d1c..74fc84da6 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -3,6 +3,9 @@ # with the command "udevadm control --reload" ACTION!="add|change", GOTO="openocd_rules_end" + +SUBSYSTEM=="gpio", MODE="0660", GROUP="plugdev", TAG+="uaccess" + SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end" # Please keep this list sorted by VID:PID commit 93be480c908d4751936ed779be1f00998c668c87 Author: Antonio Borneo <bor...@gm...> Date: Sun Mar 29 16:08:50 2020 +0200 jtag/drivers: add linuxgpiod driver New adapter driver for GPIO bitbanging over Linux GPIO descriptors through the library libgpiod. On Debian based distribution, the package libgpiod-dev is required for build. Change-Id: I1ce1a4f1ca79096d6d476b01b523c8c10f2cac07 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5559 Tested-by: jenkins diff --git a/configure.ac b/configure.ac index 382a00b6e..4d8c91635 100644 --- a/configure.ac +++ b/configure.ac @@ -137,6 +137,9 @@ m4_define([LIBFTDI_ADAPTERS], [[presto], [ASIX Presto Adapter], [PRESTO]], [[openjtag], [OpenJTAG Adapter], [OPENJTAG]]]) +m4_define([LIBGPIOD_ADAPTERS], + [[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]]) + m4_define([LIBJAYLINK_ADAPTERS], [[[jlink], [SEGGER J-Link Programmer], [JLINK]]]) @@ -241,6 +244,7 @@ AC_ARG_ADAPTERS([ HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, + LIBGPIOD_ADAPTERS, LIBJAYLINK_ADAPTERS ],[auto]) @@ -335,6 +339,10 @@ AS_CASE([$host_os], AC_MSG_ERROR([sysfsgpio is only available on linux]) ]) + AS_IF([test "x$enable_linuxgpiod" = "xyes"], [ + AC_MSG_ERROR([linuxgpiod is only available on linux]) + ]) + AS_IF([test "x$build_xlnx_pcie_xvc" = "xyes"], [ AC_MSG_ERROR([xlnx_pcie_xvc is only available on linux]) ]) @@ -643,6 +651,8 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [use_libftdi=yes], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) +PKG_CHECK_MODULES([LIBGPIOD], [libgpiod], [use_libgpiod=yes], [use_libgpiod=no]) + PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) @@ -672,6 +682,7 @@ PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) +PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [libgpiod]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) AS_IF([test "x$build_openjtag" = "xyes"], [ @@ -681,6 +692,10 @@ AS_IF([test "x$build_openjtag" = "xyes"], [ ]) ]) +AS_IF([test "x$enable_linuxgpiod" != "xno"], [ + build_bitbang=yes +]) + AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno"], [ AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) AM_CONDITIONAL([HLADAPTER], [true]) @@ -736,6 +751,7 @@ AM_CONDITIONAL([IS_WIN32], [test "x$is_win32" = "xyes"]) AM_CONDITIONAL([IS_DARWIN], [test "x$is_darwin" = "xyes"]) AM_CONDITIONAL([BITQ], [test "x$build_bitq" = "xyes"]) AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"]) +AM_CONDITIONAL([USE_LIBGPIOD], [test "x$use_libgpiod" = "xyes"]) AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"]) AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"]) AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"]) @@ -807,6 +823,7 @@ echo OpenOCD configuration summary echo -------------------------------------------------- m4_foreach([adapter], [USB1_ADAPTERS, USB0_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, + LIBGPIOD_ADAPTERS, LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS], [s=m4_format(["%-40s"], ADAPTER_DESC([adapter])) AS_CASE([$ADAPTER_VAR([adapter])], diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index b03f560b3..77d6fb2af 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -38,6 +38,11 @@ if USE_LIBFTDI %C%_libocdjtagdrivers_la_LIBADD += $(LIBFTDI_LIBS) endif +if USE_LIBGPIOD +%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBGPIOD_CFLAGS) +%C%_libocdjtagdrivers_la_LIBADD += $(LIBGPIOD_LIBS) +endif + if USE_HIDAPI %C%_libocdjtagdrivers_la_CPPFLAGS += $(HIDAPI_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(HIDAPI_LIBS) @@ -71,6 +76,9 @@ endif if FTDI DRIVERFILES += %D%/ftdi.c %D%/mpsse.c endif +if LINUXGPIOD +DRIVERFILES += %D%/linuxgpiod.c +endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c new file mode 100644 index 000000000..661a926f5 --- /dev/null +++ b/src/jtag/drivers/linuxgpiod.c @@ -0,0 +1,595 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Bitbang driver for Linux GPIO descriptors through libgpiod + * Copyright (C) 2020 Antonio Borneo <bor...@gm...> + * + * Largely based on sysfsgpio driver + * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au + * Copyright (C) 2014 by Jean-Christian de Rivaz <jc...@ec...> + * Copyright (C) 2014 by Paul Fertser <fer...@gm...> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gpiod.h> +#include <jtag/interface.h> +#include <transport/transport.h> +#include "bitbang.h" + +/* 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; +static int gpiochip = -1; + +static struct gpiod_chip *gpiod_chip; +static struct gpiod_line *gpiod_tck; +static struct gpiod_line *gpiod_tms; +static struct gpiod_line *gpiod_tdi; +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_srst; + +static int last_swclk; +static int last_swdio; +static bool last_stored; +static bool swdio_input; + +/* Bitbang interface read of TDO */ +static bb_value_t linuxgpiod_read(void) +{ + int retval; + + retval = gpiod_line_get_value(gpiod_tdo); + if (retval < 0) { + LOG_WARNING("reading tdo failed"); + return 0; + } + + return retval ? BB_HIGH : BB_LOW; +} + +/* + * Bitbang interface write of TCK, TMS, TDI + * + * Seeing as this is the only function where the outputs are changed, + * we can cache the old value to avoid needlessly writing it. + */ +static int linuxgpiod_write(int tck, int tms, int tdi) +{ + static int last_tck; + static int last_tms; + static int last_tdi; + + static int first_time; + + int retval; + + if (!first_time) { + last_tck = !tck; + last_tms = !tms; + last_tdi = !tdi; + first_time = 1; + } + + if (tdi != last_tdi) { + retval = gpiod_line_set_value(gpiod_tdi, tdi); + if (retval < 0) + LOG_WARNING("writing tdi failed"); + } + + if (tms != last_tms) { + retval = gpiod_line_set_value(gpiod_tms, tms); + if (retval < 0) + LOG_WARNING("writing tms failed"); + } + + /* write clk last */ + if (tck != last_tck) { + retval = gpiod_line_set_value(gpiod_tck, tck); + if (retval < 0) + LOG_WARNING("writing tck failed"); + } + + last_tdi = tdi; + last_tms = tms; + last_tck = tck; + + return ERROR_OK; +} + +static int linuxgpiod_swdio_read(void) +{ + int retval; + + retval = gpiod_line_get_value(gpiod_swdio); + if (retval < 0) { + LOG_WARNING("Fail read swdio"); + return 0; + } + + return retval; +} + +static void linuxgpiod_swdio_drive(bool is_output) +{ + int retval; + + /* + * FIXME: change direction requires release and re-require the line + * https://stackoverflow.com/questions/58735140/ + * this would change in future libgpiod + */ + gpiod_line_release(gpiod_swdio); + + if (is_output) { + retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1); + if (retval < 0) + LOG_WARNING("Fail request_output line swdio"); + } else { + retval = gpiod_line_request_input(gpiod_swdio, "OpenOCD"); + if (retval < 0) + LOG_WARNING("Fail request_input line swdio"); + } + + last_stored = false; + swdio_input = !is_output; +} + +static int linuxgpiod_swd_write(int swclk, int swdio) +{ + int retval; + + if (!swdio_input) { + if (!last_stored || (swdio != last_swdio)) { + retval = gpiod_line_set_value(gpiod_swdio, swdio); + if (retval < 0) + LOG_WARNING("Fail set swdio"); + } + } + + /* write swclk last */ + if (!last_stored || (swclk != last_swclk)) { + retval = gpiod_line_set_value(gpiod_swclk, swclk); + if (retval < 0) + LOG_WARNING("Fail set swclk"); + } + + last_swdio = swdio; + last_swclk = swclk; + last_stored = true; + + return ERROR_OK; +} + +static struct bitbang_interface linuxgpiod_bitbang = { + .read = linuxgpiod_read, + .write = linuxgpiod_write, + .swdio_read = linuxgpiod_swdio_read, + .swdio_drive = linuxgpiod_swdio_drive, + .swd_write = linuxgpiod_swd_write, + .blink = NULL, +}; + +/* + * Bitbang interface to manipulate reset lines SRST and TRST + * + * (1) assert or (0) deassert reset lines + */ +static int linuxgpiod_reset(int trst, int srst) +{ + int retval1 = 0, retval2 = 0; + + LOG_DEBUG("linuxgpiod_reset"); + + /* assume active low */ + if (gpiod_srst != NULL) { + retval1 = gpiod_line_set_value(gpiod_srst, srst ? 0 : 1); + if (retval1 < 0) + LOG_WARNING("set srst value failed"); + } + + /* assume active low */ + if (gpiod_trst != NULL) { + retval2 = gpiod_line_set_value(gpiod_trst, trst ? 0 : 1); + if (retval2 < 0) + LOG_WARNING("set trst value failed"); + } + + return ((retval1 < 0) || (retval2 < 0)) ? ERROR_FAIL : ERROR_OK; +} + +/* + * Helper function to determine if gpio number is valid + * + * Assume here that there will be less than 10000 gpios per gpiochip + */ +static bool is_gpio_valid(int gpio) +{ + return gpio >= 0 && gpio < 10000; +} + +static bool linuxgpiod_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 linuxgpiod_swd_mode_possible(void) +{ + if (!is_gpio_valid(swclk_gpio)) + return false; + if (!is_gpio_valid(swdio_gpio)) + return false; + return true; +} + +static inline void helper_release(struct gpiod_line *line) +{ + if (line) + gpiod_line_release(line); +} + +static int linuxgpiod_quit(void) +{ + helper_release(gpiod_srst); + helper_release(gpiod_swdio); + helper_release(gpiod_swclk); + helper_release(gpiod_trst); + helper_release(gpiod_tms); + helper_release(gpiod_tck); + helper_release(gpiod_tdi); + helper_release(gpiod_tdo); + + gpiod_chip_close(gpiod_chip); + + return ERROR_OK; +} + +static struct gpiod_line *helper_get_input_line(const char *label, unsigned int offset) +{ + struct gpiod_line *line; + int retval; + + line = gpiod_chip_get_line(gpiod_chip, offset); + if (line == NULL) { + LOG_ERROR("Error get line %s", label); + return NULL; + } + + retval = gpiod_line_request_input(line, "OpenOCD"); + if (retval < 0) { + LOG_ERROR("Error request_input line %s", label); + return NULL; + } + + return line; +} + +static struct gpiod_line *helper_get_output_line(const char *label, unsigned int offset, int val) +{ + struct gpiod_line *line; + int retval; + + line = gpiod_chip_get_line(gpiod_chip, offset); + if (line == NULL) { + LOG_ERROR("Error get line %s", label); + return NULL; + } + + retval = gpiod_line_request_output(line, "OpenOCD", val); + if (retval < 0) { + LOG_ERROR("Error request_output line %s", label); + return NULL; + } + + return line; +} + +static int linuxgpiod_init(void) +{ + LOG_INFO("Linux GPIOD JTAG/SWD bitbang driver"); + + bitbang_interface = &linuxgpiod_bitbang; + + gpiod_chip = gpiod_chip_open_by_number(gpiochip); + if (gpiod_chip == NULL) { + LOG_ERROR("Cannot open LinuxGPIOD gpiochip %d", gpiochip); + 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. + */ + + if (transport_is_jtag()) { + if (!linuxgpiod_jtag_mode_possible()) { + LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); + goto out_error; + } + + gpiod_tdo = helper_get_input_line("tdo", tdo_gpio); + if (gpiod_tdo == NULL) + goto out_error; + + gpiod_tdi = helper_get_output_line("tdi", tdi_gpio, 0); + if (gpiod_tdi == NULL) + goto out_error; + + gpiod_tck = helper_get_output_line("tck", tck_gpio, 0); + if (gpiod_tck == NULL) + goto out_error; + + gpiod_tms = helper_get_output_line("tms", tms_gpio, 1); + if (gpiod_tms == NULL) + goto out_error; + + if (is_gpio_valid(trst_gpio)) { + gpiod_trst = helper_get_output_line("trst", trst_gpio, 1); + if (gpiod_trst == NULL) + goto out_error; + } + } + + if (transport_is_swd()) { + if (!linuxgpiod_swd_mode_possible()) { + LOG_ERROR("Require swclk and swdio gpio for SWD mode"); + goto out_error; + } + + gpiod_swclk = helper_get_output_line("swclk", swclk_gpio, 1); + if (gpiod_swclk == NULL) + goto out_error; + + gpiod_swdio = helper_get_output_line("swdio", swdio_gpio, 1); + if (gpiod_swdio == NULL) + goto out_error; + } + + if (is_gpio_valid(srst_gpio)) { + gpiod_srst = helper_get_output_line("srst", srst_gpio, 1); + if (gpiod_srst == NULL) + goto out_error; + } + + return ERROR_OK; + +out_error: + linuxgpiod_quit(); + + return ERROR_JTAG_INIT_FAILED; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionums) +{ + if (CMD_ARGC == 4) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); + } else if (CMD_ARGC != 0) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(CMD, + "LinuxGPIOD nums: tck = %d, tms = %d, tdi = %d, tdo = %d", + tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); + + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tck) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); + + command_print(CMD, "LinuxGPIOD num: tck = %d", tck_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tms) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); + + command_print(CMD, "LinuxGPIOD num: tms = %d", tms_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdo) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); + + command_print(CMD, "LinuxGPIOD num: tdo = %d", tdo_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdi) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); + + command_print(CMD, "LinuxGPIOD num: tdi = %d", tdi_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_srst) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); + + command_print(CMD, "LinuxGPIOD num: srst = %d", srst_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_trst) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); + + command_print(CMD, "LinuxGPIOD num: trst = %d", trst_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_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, + "LinuxGPIOD nums: swclk = %d, swdio = %d", + swclk_gpio, swdio_gpio); + + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swclk) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); + + command_print(CMD, "LinuxGPIOD num: swclk = %d", swclk_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); + + command_print(CMD, "LinuxGPIOD num: swdio = %d", swdio_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(linuxgpiod_handle_gpiochip) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], gpiochip); + + command_print(CMD, "LinuxGPIOD gpiochip = %d", gpiochip); + return ERROR_OK; +} + +static const struct command_registration linuxgpiod_command_handlers[] = { + { + .name = "linuxgpiod_jtag_nums", + .handler = linuxgpiod_handle_jtag_gpionums, + .mode = COMMAND_CONFIG, + .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", + .usage = "tck tms tdi tdo", + }, + { + .name = "linuxgpiod_tck_num", + .handler = linuxgpiod_handle_jtag_gpionum_tck, + .mode = COMMAND_CONFIG, + .help = "gpio number for tck.", + .usage = "tck", + }, + { + .name = "linuxgpiod_tms_num", + .handler = linuxgpiod_handle_jtag_gpionum_tms, + .mode = COMMAND_CONFIG, + .help = "gpio number for tms.", + .usage = "tms", + }, + { + .name = "linuxgpiod_tdo_num", + .handler = linuxgpiod_handle_jtag_gpionum_tdo, + .mode = COMMAND_CONFIG, + .help = "gpio number for tdo.", + .usage = "tdo", + }, + { + .name = "linuxgpiod_tdi_num", + .handler = linuxgpiod_handle_jtag_gpionum_tdi, + .mode = COMMAND_CONFIG, + .help = "gpio number for tdi.", + .usage = "tdi", + }, + { + .name = "linuxgpiod_srst_num", + .handler = linuxgpiod_handle_jtag_gpionum_srst, + .mode = COMMAND_CONFIG, + .help = "gpio number for srst.", + .usage = "srst", + }, + { + .name = "linuxgpiod_trst_num", + .handler = linuxgpiod_handle_jtag_gpionum_trst, + .mode = COMMAND_CONFIG, + .help = "gpio number for trst.", + .usage = "trst", + }, + { + .name = "linuxgpiod_swd_nums", + .handler = linuxgpiod_handle_swd_gpionums, + .mode = COMMAND_CONFIG, + .help = "gpio numbers for swclk, swdio. (in that order)", + .usage = "swclk swdio", + }, + { + .name = "linuxgpiod_swclk_num", + .handler = linuxgpiod_handle_swd_gpionum_swclk, + .mode = COMMAND_CONFIG, + .help = "gpio number for swclk.", + .usage = "swclk", + }, + { + .name = "linuxgpiod_swdio_num", + .handler = linuxgpiod_handle_swd_gpionum_swdio, + .mode = COMMAND_CONFIG, + .help = "gpio number for swdio.", + .usage = "swdio", + }, + { + .name = "linuxgpiod_gpiochip", + .handler = linuxgpiod_handle_gpiochip, + .mode = COMMAND_CONFIG, + .help = "number of the gpiochip.", + .usage = "gpiochip", + }, + COMMAND_REGISTRATION_DONE +}; + +static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL }; + +static struct jtag_interface linuxgpiod_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver linuxgpiod_adapter_driver = { + .name = "linuxgpiod", + .transports = linuxgpiod_transport, + .commands = linuxgpiod_command_handlers, + + .init = linuxgpiod_init, + .quit = linuxgpiod_quit, + .reset = linuxgpiod_reset, + + .jtag_ops = &linuxgpiod_interface, + .swd_ops = &bitbang_swd, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 87ea95822..45e30c9b0 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -117,6 +117,9 @@ extern struct adapter_driver opendous_adapter_driver; #if BUILD_SYSFSGPIO == 1 extern struct adapter_driver sysfsgpio_adapter_driver; #endif +#if BUILD_LINUXGPIOD == 1 +extern struct adapter_driver linuxgpiod_adapter_driver; +#endif #if BUILD_XLNX_PCIE_XVC == 1 extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; #endif @@ -231,6 +234,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_SYSFSGPIO == 1 &sysfsgpio_adapter_driver, #endif +#if BUILD_LINUXGPIOD == 1 + &linuxgpiod_adapter_driver, +#endif #if BUILD_XLNX_PCIE_XVC == 1 &xlnx_pcie_xvc_adapter_driver, #endif commit ee86f3ef92adfe1f41ad67b4b154ee7ea0327cc8 Author: Antonio Borneo <bor...@gm...> Date: Wed Apr 1 12:03:47 2020 +0200 bcm2835gpio: enable only the transport specific gpio Change-Id: Ice6744600079d5994d628bb3b782aa36e71f862e Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5558 Tested-by: jenkins diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 77ae5668f..f868516d9 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -24,6 +24,7 @@ #endif #include <jtag/interface.h> +#include <transport/transport.h> #include "bitbang.h" #include <sys/mman.h> @@ -456,15 +457,13 @@ static int bcm2835gpio_init(void) LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver"); - if (bcm2835gpio_jtag_mode_possible()) { - if (bcm2835gpio_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)"); - } else if (bcm2835gpio_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"); + if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) { + LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); + return ERROR_JTAG_INIT_FAILED; + } + + if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) { + LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } @@ -500,31 +499,42 @@ static int bcm2835gpio_init(void) /* set 4mA drive strength, slew rate limited, hysteresis on */ pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1; - tdo_gpio_mode = MODE_GPIO(tdo_gpio); - tdi_gpio_mode = MODE_GPIO(tdi_gpio); - tck_gpio_mode = MODE_GPIO(tck_gpio); - tms_gpio_mode = MODE_GPIO(tms_gpio); - swclk_gpio_mode = MODE_GPIO(swclk_gpio); - swdio_gpio_mode = MODE_GPIO(swdio_gpio); /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ - INP_GPIO(tdo_gpio); - - GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio | 1<<swdio_gpio | 1<<swclk_gpio; - GPIO_SET = 1<<tms_gpio; - - OUT_GPIO(tdi_gpio); - OUT_GPIO(tck_gpio); - OUT_GPIO(tms_gpio); - OUT_GPIO(swclk_gpio); - OUT_GPIO(swdio_gpio); - if (trst_gpio != -1) { - trst_gpio_mode = MODE_GPIO(trst_gpio); - GPIO_SET = 1 << trst_gpio; - OUT_GPIO(trst_gpio); + if (transport_is_jtag()) { + tdo_gpio_mode = MODE_GPIO(tdo_gpio); + tdi_gpio_mode = MODE_GPIO(tdi_gpio); + tck_gpio_mode = MODE_GPIO(tck_gpio); + tms_gpio_mode = MODE_GPIO(tms_gpio); + + INP_GPIO(tdo_gpio); + + GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio; + GPIO_SET = 1<<tms_gpio; + + OUT_GPIO(tdi_gpio); + OUT_GPIO(tck_gpio); + OUT_GPIO(tms_gpio); + + if (trst_gpio != -1) { + trst_gpio_mode = MODE_GPIO(trst_gpio); + GPIO_SET = 1 << trst_gpio; + OUT_GPIO(trst_gpio); + } } + + if (transport_is_swd()) { + swclk_gpio_mode = MODE_GPIO(swclk_gpio); + swdio_gpio_mode = MODE_GPIO(swdio_gpio); + + GPIO_CLR = 1<<swdio_gpio | 1<<swclk_gpio; + + OUT_GPIO(swclk_gpio); + OUT_GPIO(swdio_gpio); + } + if (srst_gpio != -1) { srst_gpio_mode = MODE_GPIO(srst_gpio); GPIO_SET = 1 << srst_gpio; @@ -540,14 +550,20 @@ static int bcm2835gpio_init(void) static int bcm2835gpio_quit(void) { - SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode); - SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode); - SET_MODE_GPIO(tck_gpio, tck_gpio_mode); - SET_MODE_GPIO(tms_gpio, tms_gpio_mode); - SET_MODE_GPIO(swclk_gpio, swclk_gpio_mode); - SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode); - if (trst_gpio != -1) - SET_MODE_GPIO(trst_gpio, trst_gpio_mode); + if (transport_is_jtag()) { + SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode); + SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode); + SET_MODE_GPIO(tck_gpio, tck_gpio_mode); + SET_MODE_GPIO(tms_gpio, tms_gpio_mode); + if (trst_gpio != -1) + SET_MODE_GPIO(trst_gpio, trst_gpio_mode); + } + + if (transport_is_swd()) { + SET_MODE_GPIO(swclk_gpio, swclk_gpio_mode); + SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode); + } + if (srst_gpio != -1) SET_MODE_GPIO(srst_gpio, srst_gpio_mode); commit a8e483a2bf9d1b4eb16b7a0e0851b455a935fcf0 Author: Antonio Borneo <bor...@gm...> Date: Wed Apr 1 11:53:30 2020 +0200 imx_gpio: enable only the transport specific gpio Change-Id: Idb1fabbc1e9385f8c23b643584bf7863ea91ffbf Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: http://openocd.zylin.com/5557 Tested-by: jenkins Reviewed-by: Tomas Vanek <va...@fb...> diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index b96b433f7..c80e84218 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -22,6 +22,7 @@ #endif #include <jtag/interface.h> +#include <transport/transport.h> #include "bitbang.h" #include <sys/mman.h> @@ -478,15 +479,13 @@ static int imx_gpio_init(void) LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver"); - if (imx_gpio_jtag_mode_possible()) { - if (imx_gpio_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)"); - } else if (imx_gpio_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"); + if (transport_is_jtag() && !imx_gpio_jtag_mode_possible()) { + LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); + return ERROR_JTAG_INIT_FAILED; + } + + if (transport_is_swd() && !imx_gpio_swd_mode_possible()) { + LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } @@ -496,7 +495,6 @@ static int imx_gpio_init(void) return ERROR_JTAG_INIT_FAILED; } - LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u", (unsigned int) sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE); pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE, @@ -513,7 +511,7 @@ static int imx_gpio_init(void) * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ - if (imx_gpio_jtag_mode_possible()) { + if (transport_is_jtag()) { tdo_gpio_mode = gpio_mode_get(tdo_gpio); tdi_gpio_mode = gpio_mode_get(tdi_gpio); tck_gpio_mode = gpio_mode_get(tck_gpio); @@ -527,8 +525,15 @@ static int imx_gpio_init(void) gpio_mode_output_set(tdi_gpio); gpio_mode_output_set(tck_gpio); gpio_mode_output_set(tms_gpio); + + if (trst_gpio != -1) { + trst_gpio_mode = gpio_mode_get(trst_gpio); + gpio_set(trst_gpio); + gpio_mode_output_set(trst_gpio); + } } - if (imx_gpio_swd_mode_possible()) { + + if (transport_is_swd()) { swclk_gpio_mode = gpio_mode_get(swclk_gpio); swdio_gpio_mode = gpio_mode_get(swdio_gpio); @@ -537,11 +542,7 @@ static int imx_gpio_init(void) gpio_mode_output_set(swclk_gpio); gpio_mode_output_set(swdio_gpio); } - if (trst_gpio != -1) { - trst_gpio_mode = gpio_mode_get(trst_gpio); - gpio_set(trst_gpio); - gpio_mode_output_set(trst_gpio); - } + if (srst_gpio != -1) { srst_gpio_mode = gpio_mode_get(srst_gpio); gpio_set(srst_gpio); @@ -557,18 +558,21 @@ static int imx_gpio_init(void) static int imx_gpio_quit(void) { - if (imx_gpio_jtag_mode_possible()) { + if (transport_is_jtag()) { gpio_mode_set(tdo_gpio, tdo_gpio_mode); gpio_mode_set(tdi_gpio, tdi_gpio_mode); gpio_mode_set(tck_gpio, tck_gpio_mode); gpio_mode_set(tms_gpio, tms_gpio_mode); + + if (trst_gpio != -1) + gpio_mode_set(trst_gpio, trst_gpio_mode); } - if (imx_gpio_swd_mode_possible()) { + + if (transport_is_swd()) { gpio_mode_set(swclk_gpio, swclk_gpio_mode); gpio_mode_set(swdio_gpio, swdio_gpio_mode); } - if (trst_gpio != -1) - gpio_mode_set(trst_gpio, trst_gpio_mode); + if (srst_gpio != -1) gpio_mode_set(srst_gpio, srst_gpio_mode); ----------------------------------------------------------------------- Summary of changes: configure.ac | 17 ++ contrib/60-openocd.rules | 3 + src/jtag/drivers/Makefile.am | 8 + src/jtag/drivers/bcm2835gpio.c | 90 ++++--- src/jtag/drivers/imx_gpio.c | 46 ++-- src/jtag/drivers/linuxgpiod.c | 595 +++++++++++++++++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + tcl/interface/dln-2-gpiod.cfg | 25 ++ 8 files changed, 732 insertions(+), 58 deletions(-) create mode 100644 src/jtag/drivers/linuxgpiod.c create mode 100644 tcl/interface/dln-2-gpiod.cfg hooks/post-receive -- Main OpenOCD repository |