The patch adds a cable driver that uses GPIOs to control the JTAG interface. It requires that the GPIOs sysfs is enabled on the system. The GPIOs required are passed to the driver at the connect time.
Signed-off-by: Stefano Babic <[email protected]> --- Changes since V2: - drop static arrays - avoid string indirection - some code styling urjtag/configure.ac | 1 + urjtag/include/urjtag/cable.h | 4 + urjtag/po/POTFILES.in | 1 + urjtag/src/tap/Makefile.am | 5 + urjtag/src/tap/cable.c | 4 + urjtag/src/tap/cable/gpio.c | 411 +++++++++++++++++++++++++++++++++++++++++ urjtag/src/tap/cable_list.h | 3 + 7 files changed, 429 insertions(+), 0 deletions(-) create mode 100644 urjtag/src/tap/cable/gpio.c diff --git a/urjtag/configure.ac b/urjtag/configure.ac index 515ddea..6f63358 100644 --- a/urjtag/configure.ac +++ b/urjtag/configure.ac @@ -645,6 +645,7 @@ URJ_DRIVER_SET([cable], [ ea253 ei012 ft2232 + gpio ice100 igloo jlink diff --git a/urjtag/include/urjtag/cable.h b/urjtag/include/urjtag/cable.h index f5f95a7..dd79187 100644 --- a/urjtag/include/urjtag/cable.h +++ b/urjtag/include/urjtag/cable.h @@ -59,6 +59,10 @@ typedef enum URJ_CABLE_PARAM_KEY URJ_CABLE_PARAM_KEY_DESC, /* string generic_usbconn */ URJ_CABLE_PARAM_KEY_DRIVER, /* string generic_usbconn */ URJ_CABLE_PARAM_KEY_BITMAP, /* string wiggler */ + URJ_CABLE_PARAM_KEY_TDI, /* lu gpio used as TDI */ + URJ_CABLE_PARAM_KEY_TDO, /* lu gpio used as TDO */ + URJ_CABLE_PARAM_KEY_TMS, /* lu gpio used as TMS */ + URJ_CABLE_PARAM_KEY_TCK, /* lu gpio used as TCK */ } urj_cable_param_key_t; diff --git a/urjtag/po/POTFILES.in b/urjtag/po/POTFILES.in index 320fc0c..fcdfddd 100644 --- a/urjtag/po/POTFILES.in +++ b/urjtag/po/POTFILES.in @@ -114,6 +114,7 @@ src/tap/cable/ft2232.c src/tap/cable/generic.c src/tap/cable/generic_parport.c src/tap/cable/generic_usbconn.c +src/tap/cable/gpio.c src/tap/cable/jim.c src/tap/cable/jlink.c src/tap/cable/keithkoep.c diff --git a/urjtag/src/tap/Makefile.am b/urjtag/src/tap/Makefile.am index b539583..d7d6691 100644 --- a/urjtag/src/tap/Makefile.am +++ b/urjtag/src/tap/Makefile.am @@ -77,6 +77,11 @@ libtap_la_SOURCES += \ cable/ei012.c endif +if ENABLE_CABLE_GPIO +libtap_la_SOURCES += \ + cable/gpio.c +endif + if ENABLE_CABLE_KEITHKOEP libtap_la_SOURCES += \ cable/keithkoep.c diff --git a/urjtag/src/tap/cable.c b/urjtag/src/tap/cable.c index 2d9854d..c58c3c7 100644 --- a/urjtag/src/tap/cable.c +++ b/urjtag/src/tap/cable.c @@ -668,6 +668,10 @@ static const urj_param_descr_t cable_param[] = { URJ_CABLE_PARAM_KEY_DESC, URJ_PARAM_TYPE_STRING, "desc", }, { URJ_CABLE_PARAM_KEY_DRIVER, URJ_PARAM_TYPE_STRING, "driver", }, { URJ_CABLE_PARAM_KEY_BITMAP, URJ_PARAM_TYPE_STRING, "bitmap", }, + { URJ_CABLE_PARAM_KEY_TDI, URJ_PARAM_TYPE_LU, "tdi", }, + { URJ_CABLE_PARAM_KEY_TDO, URJ_PARAM_TYPE_LU, "tdo", }, + { URJ_CABLE_PARAM_KEY_TMS, URJ_PARAM_TYPE_LU, "tms", }, + { URJ_CABLE_PARAM_KEY_TCK, URJ_PARAM_TYPE_LU, "tck", }, }; const urj_param_list_t urj_cable_param_list = diff --git a/urjtag/src/tap/cable/gpio.c b/urjtag/src/tap/cable/gpio.c new file mode 100644 index 0000000..f5a3751 --- /dev/null +++ b/urjtag/src/tap/cable/gpio.c @@ -0,0 +1,411 @@ +/* + * (C) Copyright 2010 + * Stefano Babic, DENX Software Engineering, [email protected]. + * GPIO JTAG Cable Driver + * + * Based on TS7800 GPIO JTAG Cable Driver + * Copyright (C) 2008 Catalin Ionescu + * + * 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. + * + */ + +#include <sysdep.h> + +#include <stdlib.h> +#include <string.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <urjtag/cable.h> +#include <urjtag/parport.h> +#include <urjtag/chain.h> +#include <urjtag/cmd.h> + +#include "generic.h" + +#define GPIO_PATH "/sys/class/gpio/" +#define GPIO_EXPORT_PATH "/sys/class/gpio/export" +#define GPIO_UNEXPORT_PATH "/sys/class/gpio/unexport" + +/* pin mapping */ +enum { + GPIO_TDI = 0, + GPIO_TCK, + GPIO_TMS, + GPIO_TDO, + GPIO_REQUIRED +}; + +typedef struct { + unsigned int jtag_gpios[4]; + int signals; + uint32_t lastout; + FILE *fp_gpios[4]; +} gpio_params_t; + +static int gpio_export (int gpio, int export) +{ + int ret; + char *fname; + FILE *fp; + + if (export) + fname = GPIO_EXPORT_PATH; + else + fname = GPIO_UNEXPORT_PATH; + + fp = fopen (fname, "w"); + if (!fp) { + urj_warning ( + _("File %s cannot be opened to (un)export GPIO %d: %d\n"), fname, gpio, errno); + return -1; + } + + ret = fprintf (fp, "%u", gpio); + fclose (fp); + + return 0; +} + +static int gpio_direction (int gpio_number, int out) +{ + int ret; + char fname[50]; + FILE *fp; + + snprintf (fname, sizeof(fname), + "%sgpio%d/direction", GPIO_PATH, gpio_number); + + fp = fopen (fname, "w"); + if (!fp) { + urj_warning ( _("File %s cannot be opened to set direction\n"), fname); + return -1; + } + + ret = fprintf (fp, "%s", out ? "out" : "in"); + fclose (fp); + + if (ret != strlen (out ? "out" : "in")) { + urj_warning ( + _("Error setting direction gpio %d %s %d\n"), + gpio_number, out ? "out" : "in", ret); + return -1; + } + + return 0; +} + +static int gpio_set_value (FILE *fp, int value) +{ + int ret; + + ret = fprintf (fp, "%u", value ? 1 : 0); + if (ret != 1) { + urj_warning ( _("%s setting value gpio\n"), strerror(errno)); + return -1; + } + + return 0; +} + +static int gpio_get_value (int gpio) +{ + int ret; + char buf[8]; + char fname[50]; + FILE *fp; + + snprintf (fname, sizeof(fname), + "%sgpio%d/value", GPIO_PATH, gpio); + + fp = fopen (fname, "r"); + if (!fp) { + urj_warning ( _("File %s cannot be opened to read GPIO %d\n"), fname, gpio); + return -1; + } + + ret = fscanf (fp, "%c", buf); + fclose (fp); + + if (ret != 1) { + urj_warning ( + _("Error getting value gpio %d\n"), errno); + return -1; + } + + if (buf[0] != '0' && buf[0] != '1') { + urj_warning(_("Erroneous value for gpio %d: 0x%x\n"), gpio, buf[0]); + return -1; + } + + return buf[0] - '0'; +} + + + +static int +gpio_open (urj_cable_t *cable) +{ + gpio_params_t *p = cable->params; + char fname[50]; + int i, ret; + + /* Export all gpios */ + for (i = 0; i < GPIO_REQUIRED; i++) { + ret = gpio_export (p->jtag_gpios[i], 1); + + if (ret) { + urj_warning ( _("gpio (%d) cannot be exported\n"), i); + return -1; + } + gpio_direction (p->jtag_gpios[i], (i == GPIO_TDO) ? 0 : 1); + p->fp_gpios[i] = NULL; + fname[sizeof(fname) - 1] = '\0'; + snprintf (fname, sizeof(fname), + "%sgpio%d/value", GPIO_PATH, p->jtag_gpios[i]); + if (i != GPIO_TDO) + p->fp_gpios[i] = fopen (fname, "w"); + else + p->fp_gpios[i] = fopen (fname, "r"); + if (!p->fp_gpios[i]) { + urj_warning ( _("File %s cannot be opened for gpio(%d)\n"), fname, i); + return -1; + } + if (setvbuf(p->fp_gpios[i], (char *)NULL, _IONBF, 0)) { + urj_warning ( _("gpio(%d) still in buffered mode\n"), i); + return -1; + } + } + + return URJ_STATUS_OK; +} + +static int +gpio_close (urj_cable_t *cable) +{ + int i; + gpio_params_t *p = cable->params; + + for (i = 0; i < GPIO_REQUIRED; i++) { + if (p->fp_gpios[i]) fclose (p->fp_gpios[i]); + gpio_export (p->jtag_gpios[i], 0); + } + + return URJ_STATUS_OK; +} + +static void +gpio_help (urj_log_level_t ll, const char *cablename) +{ + urj_log (ll, + _("Usage: cable %s tdi=<gpio_tdi> tdo=<gpio_tdo> " + "tck=<gpio_tck> tms=<gpio_tms>\n" + "\n"), cablename ); +} + +static int +gpio_connect (urj_cable_t *cable, const urj_param_t *params[]) +{ + gpio_params_t *cable_params; + int i; + + cable_params = calloc (1, sizeof *cable_params); + if (!cable_params) { + urj_error_set (URJ_ERROR_OUT_OF_MEMORY, _("malloc(%zd) fails"), + sizeof *cable_params); + free (cable); + return URJ_STATUS_FAIL; + } + + if (params != NULL) + /* parse arguments beyond the cable name */ + for (i = 0; params[i] != NULL; i++) + { + switch (params[i]->key) + { + case URJ_CABLE_PARAM_KEY_TDI: + cable_params->jtag_gpios[GPIO_TDI] = params[i]->value.lu; + break; + case URJ_CABLE_PARAM_KEY_TDO: + cable_params->jtag_gpios[GPIO_TDO] = params[i]->value.lu; + break; + case URJ_CABLE_PARAM_KEY_TMS: + cable_params->jtag_gpios[GPIO_TMS] = params[i]->value.lu; + break; + case URJ_CABLE_PARAM_KEY_TCK: + cable_params->jtag_gpios[GPIO_TCK] = params[i]->value.lu; + break; + default: + break; + } + } + + urj_log (URJ_LOG_LEVEL_NORMAL, + _("Initializing GPIO JTAG Chain\n") ); + + /* + * We need to configure the cable only once. Next time + * is called, the old parameters are taken if a newer + * is not passed + */ + + for (i = GPIO_TDI; i <= GPIO_TDO; i++) { + if (cable_params->jtag_gpios[i] < 0) { + urj_log (URJ_LOG_LEVEL_NORMAL, + _("Error: you must configure the gpios you need!\n") ); + gpio_help (URJ_LOG_LEVEL_NORMAL, (const char *)params[0]); + return 1; + } + } + + cable->params = cable_params; + cable->chain = NULL; + cable->delay = 1000; + + return URJ_STATUS_OK; +} + +static void +gpio_disconnect (urj_cable_t *cable) +{ + urj_tap_chain_disconnect (cable->chain); + gpio_close (cable); +} + +static void +gpio_cable_free (urj_cable_t *cable) +{ + free (cable->params); + free (cable); +} + +static int +gpio_init (urj_cable_t *cable) +{ + gpio_params_t *p = cable->params; + + if (gpio_open (cable) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + p->signals = URJ_POD_CS_TRST; + + return URJ_STATUS_OK; +} + +static void +gpio_done (urj_cable_t *cable) +{ + gpio_close (cable); +} + +static void +gpio_clock (urj_cable_t *cable, int tms, int tdi, int n) +{ + gpio_params_t *p = cable->params; + int i; + + tms = tms ? 1 : 0; + tdi = tdi ? 1 : 0; + + gpio_set_value (p->fp_gpios[GPIO_TMS], tms); + gpio_set_value (p->fp_gpios[GPIO_TDI], tdi); + + for (i = 0; i < n; i++) { + gpio_set_value (p->fp_gpios[GPIO_TCK], 0); + gpio_set_value (p->fp_gpios[GPIO_TCK], 1); + gpio_set_value (p->fp_gpios[GPIO_TCK], 0); + } +} + +static int +gpio_get_tdo ( urj_cable_t *cable ) +{ + gpio_params_t *p = cable->params; + + gpio_set_value(p->fp_gpios[GPIO_TCK], 0); + gpio_set_value(p->fp_gpios[GPIO_TDI], 0); + gpio_set_value(p->fp_gpios[GPIO_TMS], 0); + p->lastout &= ~(URJ_POD_CS_TMS | URJ_POD_CS_TDI | URJ_POD_CS_TCK); + + urj_tap_cable_wait (cable); + + return (gpio_get_value (p->jtag_gpios[GPIO_TDO])); +} + +static int +gpio_current_signals (urj_cable_t *cable) +{ + gpio_params_t *p = cable->params; + + int sigs = p->signals & ~(URJ_POD_CS_TMS | URJ_POD_CS_TDI | URJ_POD_CS_TCK); + + if (p->lastout & URJ_POD_CS_TCK) sigs |= URJ_POD_CS_TCK; + if (p->lastout & URJ_POD_CS_TDI) sigs |= URJ_POD_CS_TDI; + if (p->lastout & URJ_POD_CS_TMS) sigs |= URJ_POD_CS_TMS; + + return sigs; +} + +static int +gpio_set_signal (urj_cable_t *cable, int mask, int val) +{ + int prev_sigs = gpio_current_signals (cable); + gpio_params_t *p = cable->params; + + mask &= (URJ_POD_CS_TDI | URJ_POD_CS_TCK | URJ_POD_CS_TMS); // only these can be modified + + if (mask != 0) { + if (mask & URJ_POD_CS_TMS) + gpio_set_value (p->fp_gpios[GPIO_TMS], val & URJ_POD_CS_TMS); + if (mask & URJ_POD_CS_TDI) + gpio_set_value (p->fp_gpios[GPIO_TDI], val & URJ_POD_CS_TDI); + if (mask & URJ_POD_CS_TCK) + gpio_set_value (p->fp_gpios[GPIO_TCK], val & URJ_POD_CS_TCK); + } + + p->lastout = val & mask; + + return prev_sigs; +} + +static int +gpio_get_signal (urj_cable_t *cable, urj_pod_sigsel_t sig) +{ + return (gpio_current_signals (cable) & sig) ? 1 : 0; +} + +const urj_cable_driver_t urj_tap_cable_gpio_driver = { + "gpio", + N_("GPIO JTAG Chain"), + URJ_CABLE_DEVICE_OTHER, + { .other = gpio_connect, }, + gpio_disconnect, + gpio_cable_free, + gpio_init, + gpio_done, + urj_tap_cable_generic_set_frequency, + gpio_clock, + gpio_get_tdo, + urj_tap_cable_generic_transfer, + gpio_set_signal, + gpio_get_signal, + urj_tap_cable_generic_flush_one_by_one, + gpio_help +}; + diff --git a/urjtag/src/tap/cable_list.h b/urjtag/src/tap/cable_list.h index 123b267..f7c9d02 100644 --- a/urjtag/src/tap/cable_list.h +++ b/urjtag/src/tap/cable_list.h @@ -59,6 +59,9 @@ _URJ_CABLE(ft2232_turtelizer2) _URJ_CABLE(ft2232_usbscarab2) _URJ_CABLE(ft2232_usbtojtagif) #endif +#ifdef ENABLE_CABLE_GPIO +_URJ_CABLE(gpio) +#endif #ifdef ENABLE_CABLE_ICE100 _URJ_CABLE(ice100B) _URJ_CABLE(ezkit_10) -- 1.6.3.3 ------------------------------------------------------------------------------ The Palm PDK Hot Apps Program offers developers who use the Plug-In Development Kit to bring their C/C++ apps to Palm for a share of $1 Million in cash or HP Products. Visit us here for more details: http://p.sf.net/sfu/dev2dev-palm _______________________________________________ UrJTAG-development mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/urjtag-development
