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]>
---
 configure.ac         |    3 +-
 po/POTFILES.in       |    1 +
 src/tap/Makefile.am  |    5 +
 src/tap/cable.c      |    4 +
 src/tap/cable/gpio.c |  423 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 435 insertions(+), 1 deletions(-)
 create mode 100644 src/tap/cable/gpio.c

diff --git a/configure.ac b/configure.ac
index 8737097..a4b52aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -468,7 +468,7 @@ CHECK_DRIVER([$busdrivers], [enabled_bus_drivers], 
[zefant_xs3],    [ENABLE_BUS_
 
 # Enable cable drivers
 AC_DEFUN([DEF_ENABLE_CABLEDRIVERS], [\
-arcom byteblaster dlc5 ea253 ei012 ft2232 igloo jlink keithkoep lattice mpcbdm 
triton usbblaster wiggler xpc])
+arcom byteblaster dlc5 ea253 ei012 ft2232 igloo jlink keithkoep lattice mpcbdm 
gpio triton usbblaster wiggler xpc])
 AC_DEFUN([DEF_DISABLE_CABLEDRIVERS], [ep9307 jim ts7800])
 AC_ARG_ENABLE(cable,
 [AS_HELP_STRING([--enable-cable], [Enable default set or specific cable 
drivers.])]
@@ -507,6 +507,7 @@ CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], 
[jlink],       [ENABLE_CA
 CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [keithkoep],   
[ENABLE_CABLE_KEITHKOEP])
 CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [lattice],     
[ENABLE_CABLE_LATTICE])
 CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [mpcbdm],      
[ENABLE_CABLE_MPCBDM])
+CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [gpio],        
[ENABLE_CABLE_GPIO])
 CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [triton],      
[ENABLE_CABLE_TRITON])
 CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [usbblaster],  
[ENABLE_CABLE_USBBLASTER])
 CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [wiggler],     
[ENABLE_CABLE_WIGGLER])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 37a4453..f7c3102 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -116,6 +116,7 @@ src/tap/cable/jlink.c
 src/tap/cable/keithkoep.c
 src/tap/cable/lattice.c
 src/tap/cable/mpcbdm.c
+src/tap/cable/gpio.c
 src/tap/cable/triton.c
 src/tap/cable/ts7800.c
 src/tap/cable/usbblaster.c
diff --git a/src/tap/Makefile.am b/src/tap/Makefile.am
index e0defd5..2422280 100644
--- a/src/tap/Makefile.am
+++ b/src/tap/Makefile.am
@@ -85,6 +85,11 @@ libtap_a_SOURCES += \
        cable/mpcbdm.c
 endif
 
+if ENABLE_CABLE_GPIO
+libtap_a_SOURCES += \
+       cable/gpio.c
+endif
+
 if ENABLE_CABLE_TRITON
 libtap_a_SOURCES += \
        cable/triton.c
diff --git a/src/tap/cable.c b/src/tap/cable.c
index c8945fd..d09ef0b 100644
--- a/src/tap/cable.c
+++ b/src/tap/cable.c
@@ -59,6 +59,7 @@ extern cable_driver_t igloo_cable_driver;
 extern cable_driver_t keithkoep_cable_driver;
 extern cable_driver_t lattice_cable_driver;
 extern cable_driver_t mpcbdm_cable_driver;
+extern cable_driver_t gpio_cable_driver;
 extern cable_driver_t triton_cable_driver;
 extern cable_driver_t jim_cable_driver;
 extern cable_driver_t wiggler_cable_driver;
@@ -116,6 +117,9 @@ cable_driver_t *cable_drivers[] = {
 #ifdef ENABLE_CABLE_MPCBDM
        &mpcbdm_cable_driver,
 #endif
+#ifdef ENABLE_CABLE_GPIO
+       &gpio_cable_driver,
+#endif
 #ifdef ENABLE_CABLE_TRITON
        &triton_cable_driver,
 #endif
diff --git a/src/tap/cable/gpio.c b/src/tap/cable/gpio.c
new file mode 100644
index 0000000..4d8ffb5
--- /dev/null
+++ b/src/tap/cable/gpio.c
@@ -0,0 +1,423 @@
+/*
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, [email protected].
+ * QONG 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "cable.h"
+#include "chain.h"
+
+#include "generic.h"
+
+#include <cmd.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
+};
+
+static int gpios[] = {
+       [GPIO_TDI] = -1,
+       [GPIO_TCK] = -1,
+       [GPIO_TMS] = -1,
+       [GPIO_TDO] = -1 
+};
+
+typedef struct {
+       int             signals;
+       uint32_t        lastout;
+       int             fd_gpios[4];
+} gpio_params_t;
+
+static int gpio_export(int gpio, int export) {
+
+       int fd, ret;
+       char *fname;
+       char gpio_number[10];
+
+       if (export)
+               fname = GPIO_EXPORT_PATH;
+       else
+               fname = GPIO_UNEXPORT_PATH;
+
+       fd = open(fname, O_WRONLY);
+       if (!fd) {
+               printf("I cannot open %s to (un)export GPIO %d: %d\n", fname, 
gpio, errno);
+               return -1;
+       }
+
+       snprintf(gpio_number, sizeof(gpio_number) - 2, "%d\n", gpio);
+
+       ret = write(fd,gpio_number, strlen(gpio_number));
+       close(fd);
+
+       return 0;
+}
+
+static int gpio_direction(int gpio_number, int out)
+{
+       int fd, ret;
+       char fname[50];
+       char buf[8];
+
+       memset(fname, 0, sizeof(fname));
+       memset(buf, 0, sizeof(buf));
+       snprintf(fname, sizeof(fname),
+               "%sgpio%d/direction", GPIO_PATH, gpio_number);
+
+       fd = open(fname, O_WRONLY);
+       if (!fd) {
+               printf("I cannot open %s to set GPIO\n", fname);
+               return -1;
+       }
+
+       if (out)
+               strcpy(buf, "out");
+       else
+               strcpy(buf, "in");
+
+       ret = write(fd,buf, strlen(buf));
+       close(fd);
+
+       if (ret != strlen(buf)) {
+               printf("Error setting direction gpio %d %s %d\n",
+                       gpio_number, out ? "out" : "in", ret);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int gpio_set_value(int fd, int value) {
+       int ret;
+       char buf[8];
+
+       buf[0] = value + '0';
+
+       ret = write(fd, buf, 1);
+
+       if (ret != 1) {
+               printf("Error %d setting value gpio\n", ret);
+               return -1;
+       }
+
+       return 0;
+}
+
+int gpio_get_value(int gpio) {
+       int ret;
+       char buf[8];
+       int fd;
+       char fname[50];
+
+       snprintf(fname, sizeof(fname),
+               "%sgpio%d/value", GPIO_PATH, gpio);
+
+       fd = open(fname, O_RDONLY);
+       if (!fd) {
+               printf("I cannot open %s to read GPIO %d\n", fname, gpio);
+               return -1;
+       }
+
+       ret = read(fd, buf, 8);
+       close(fd);
+
+       if (ret <= 0) {
+               printf("Error getting value gpio %d\n", errno);
+               return -1;
+       }
+
+       if (buf[0] != '0' && buf[0] != '1') {
+               printf("Erroneous value for gpio %d: 0x%x\n", gpio, buf[0]);
+               return -1;
+       }
+
+       return buf[0] - '0';
+}
+
+
+
+static int
+gpio_open( cable_t *cable )
+{
+       gpio_params_t *p = cable->params;
+       char fname[50];
+       int i, ret;
+
+       /* Export all gpios */
+       for (i = 0; i < sizeof(gpios) / sizeof(gpios[0]); i++) {        
+               ret = gpio_export(gpios[i], 1);
+
+               if (ret) {
+                       printf ("I cannot export gpio (index) %d\n", i);
+                       return -1;
+               }
+               gpio_direction(gpios[i], (i == GPIO_TDO) ? 0 : 1);
+               if (i != GPIO_TDO) {
+                       memset(fname, 0, sizeof(fname));
+                       snprintf(fname, sizeof(fname),
+                               "%sgpio%d/value", GPIO_PATH, gpios[i]);
+                       p->fd_gpios[i] = open(fname, O_RDWR);
+                       if (!p->fd_gpios[i]) {
+                               printf ("I cannot open value for gpio(%d)\n", 
i);
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int
+gpio_close( cable_t *cable )
+{
+       int i;
+       gpio_params_t *p = cable->params;
+
+       for (i = 0; i < sizeof(gpios) / sizeof(gpios[0]); i++) {        
+               if (p->fd_gpios[i]) close(p->fd_gpios[i]);
+               gpio_export(gpios[i], 0);
+       }
+
+       return 0;
+}
+
+static void
+gpio_help( const char *cablename )
+{
+       printf( _(
+               "Usage: cable %s tdi=<gpio_tdi> tdo=<gpio_tdo> "
+               "tck=<gpio_tck> tms=<gpio_tms>\n"
+               "\n"
+       ), cablename );
+}
+
+static int
+gpio_connect( char *params[], cable_t *cable )
+{
+       gpio_params_t *cable_params;
+       int paramc = cmd_params( params );
+       int i;
+
+       /* Parse parameters to get which gpios are connected to JTAG */
+       for (i = 0; i < paramc; i++)
+       {
+               if(strncasecmp("tdi=", params[i], 4) == 0)
+               {
+                       gpios[GPIO_TDI] = strtol( params[i] + 4, NULL, 10 );
+               }
+               if(strncasecmp("tdo=", params[i], 4) == 0)
+               {
+                       gpios[GPIO_TDO] = strtol( params[i] + 4, NULL, 10 );
+               }
+               if(strncasecmp("tms=", params[i], 4) == 0)
+               {
+                       gpios[GPIO_TMS] = strtol( params[i] + 4, NULL, 10 );
+               }
+               if(strncasecmp("tck=", params[i], 4) == 0)
+               {
+                       gpios[GPIO_TCK] = strtol( params[i] + 4, NULL, 10 );
+               }
+       }
+
+       printf( _("Initializing QONG 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 (gpios[i] < 0) {
+                       printf( _("Error: you must configure the gpios you 
need!\n") );
+                       gpio_help(params[0]);
+                       return 1;
+               }
+       }
+
+       cable_params = malloc( sizeof(gpio_params_t));
+       if (!cable_params) {
+               printf( _("%s(%d) Out of memory\n"), __FILE__, __LINE__ );
+               free( cable );
+               return 4;
+       }
+       memset(cable_params, 0, sizeof(gpio_params_t));
+
+       cable->params = cable_params;
+       cable->chain = NULL;
+       cable->delay = 1000;
+
+       return 0;
+}
+
+static void
+gpio_disconnect( cable_t *cable )
+{
+       gpio_close( cable );
+       chain_disconnect( cable->chain );
+}
+
+static void
+gpio_cable_free( cable_t *cable )
+{
+       free( cable->params );
+       free( cable );
+}
+
+static int
+gpio_init( cable_t *cable )
+{
+       gpio_params_t *p = cable->params;
+
+       if (gpio_open( cable ))
+               return -1;
+
+       p->signals = CS_TRST;
+
+       return 0;
+}
+
+static void
+gpio_done( cable_t *cable )
+{
+       gpio_close( cable );
+}
+
+static void
+gpio_clock( cable_t *cable, int tms, int tdi, int n )
+{
+       gpio_params_t *p = cable->params;
+       int bit_mask;
+       int i;
+
+       tms = tms ? 1 : 0;
+       tdi = tdi ? 1 : 0;
+
+       gpio_set_value(p->fd_gpios[GPIO_TMS], tms);
+       gpio_set_value(p->fd_gpios[GPIO_TDI], tdi);
+
+       for (i = 0; i < n; i++) {
+               gpio_set_value(p->fd_gpios[GPIO_TCK], 0);
+               gpio_set_value(p->fd_gpios[GPIO_TCK], 1);
+               gpio_set_value(p->fd_gpios[GPIO_TCK], 0);
+       }
+}
+
+/*
+ * NOTE: This also lowers the TDI and TMS lines; is this intended?
+ */
+static int
+gpio_get_tdo( cable_t *cable )
+{
+       gpio_params_t *p = cable->params;
+
+       gpio_set_value(p->fd_gpios[GPIO_TCK], 0);
+       gpio_set_value(p->fd_gpios[GPIO_TDI], 0);
+       gpio_set_value(p->fd_gpios[GPIO_TMS], 0);
+       p->lastout &= ~(CS_TMS | CS_TDI | CS_TCK);
+
+       cable_wait( cable );
+
+       return (gpio_get_value(gpios[GPIO_TDO]));
+}
+
+static int
+gpio_current_signals( cable_t *cable )
+{
+       gpio_params_t *p = cable->params;
+
+       int sigs = p->signals & ~(CS_TMS | CS_TDI | CS_TCK);
+
+       if (p->lastout & CS_TCK) sigs |= CS_TCK;
+       if (p->lastout & CS_TDI) sigs |= CS_TDI;
+       if (p->lastout & CS_TMS) sigs |= CS_TMS;
+
+       return sigs;
+}
+
+static int
+gpio_set_signal( cable_t *cable, int mask, int val )
+{
+       int prev_sigs = gpio_current_signals( cable );
+       gpio_params_t *p = cable->params;
+
+       mask &= (CS_TDI | CS_TCK | CS_TMS); // only these can be modified
+
+       if (mask != 0) {
+               if (mask & CS_TMS)
+                       gpio_set_value(p->fd_gpios[GPIO_TMS], val & CS_TMS);
+               if (mask & CS_TDI)
+                       gpio_set_value(p->fd_gpios[GPIO_TDI], val & CS_TDI);
+               if (mask & CS_TCK)
+                       gpio_set_value(p->fd_gpios[GPIO_TCK], val & CS_TCK);
+       }
+
+       p->lastout = val & mask;
+
+       return prev_sigs;
+}
+
+static int
+gpio_get_signal( cable_t *cable, pod_sigsel_t sig )
+{
+       return (gpio_current_signals( cable ) & sig) ? 1 : 0;
+}
+
+cable_driver_t gpio_cable_driver = {
+       "gpio",
+       N_("GPIO JTAG Chain"),
+       gpio_connect,
+       gpio_disconnect,
+       gpio_cable_free,
+       gpio_init,
+       gpio_done,
+       generic_set_frequency,
+       gpio_clock,
+       gpio_get_tdo,
+       generic_transfer,
+       gpio_set_signal,
+       gpio_get_signal,
+       generic_flush_one_by_one,
+       gpio_help
+};
+
-- 
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

Reply via email to