]> git.sur5r.net Git - openocd/blobdiff - src/jtag/drivers/ft2232.c
arm-jtag-ew: -Wshadow fix
[openocd] / src / jtag / drivers / ft2232.c
index 5c6b655ce88aa68ed3064e92a8931b89ff9b089c..2ac410a5d968a056d2b5e23efdafa60a5a1fb13e 100644 (file)
  * JTAG adapters based on the FT2232 full and high speed USB parts are
  * popular low cost JTAG debug solutions.  Many FT2232 based JTAG adapters
  * are discrete, but development boards may integrate them as alternatives
- * to more capable (and expensive) third party JTAG pods.  Since JTAG uses
- * only one of the two ports on these devices, on integrated boards the
- * second port often serves as a USB-to-serial adapter for the target's
- * console UART even when the JTAG port is not in use.  (Systems which
- * support ARM's SWD in addition to JTAG, or instead of it, may use that
- * second port for reading SWV trace data.)
+ * to more capable (and expensive) third party JTAG pods.
+ *
+ * JTAG uses only one of the two communications channels ("MPSSE engines")
+ * on these devices.  Adapters based on FT4232 parts have four ports/channels
+ * (A/B/C/D), instead of just two (A/B).
+ *
+ * Especially on development boards integrating one of these chips (as
+ * opposed to discrete pods/dongles), the additional channels can be used
+ * for a variety of purposes, but OpenOCD only uses one channel at a time.
+ *
+ *  - As a USB-to-serial adapter for the target's console UART ...
+ *    which may be able to support ROM boot loaders that load initial
+ *    firmware images to flash (or SRAM).
+ *
+ *  - On systems which support ARM's SWD in addition to JTAG, or instead
+ *    of it, that second port can be used for reading SWV/SWO trace data.
+ *
+ *  - Additional JTAG links, e.g. to a CPLD or * FPGA.
  *
  * FT2232 based JTAG adapters are "dumb" not "smart", because most JTAG
  * request/response interactions involve round trips over the USB link.
 /* FT2232 access library includes */
 #if BUILD_FT2232_FTD2XX == 1
 #include <ftd2xx.h>
+
+enum ftdi_interface
+{
+    INTERFACE_ANY = 0,
+    INTERFACE_A   = 1,
+    INTERFACE_B   = 2,
+    INTERFACE_C   = 3,
+    INTERFACE_D   = 4
+};
+
 #elif BUILD_FT2232_LIBFTDI == 1
 #include <ftdi.h>
 #endif
@@ -131,7 +153,6 @@ static int ft2232_stableclocks(int num_cycles, struct jtag_command* cmd);
 static char *       ft2232_device_desc_A = NULL;
 static char*        ft2232_device_desc = NULL;
 static char*        ft2232_serial  = NULL;
-static char*        ft2232_layout  = NULL;
 static uint8_t         ft2232_latency = 2;
 static unsigned                ft2232_max_tck = FTDI_2232C_MAX_TCK;
 
@@ -151,6 +172,8 @@ struct ft2232_layout {
 /* init procedures for supported layouts */
 static int usbjtag_init(void);
 static int jtagkey_init(void);
+static int lm3s811_jtag_init(void);
+static int icdi_jtag_init(void);
 static int olimex_jtag_init(void);
 static int flyswatter_init(void);
 static int turtle_init(void);
@@ -160,11 +183,13 @@ static int axm0432_jtag_init(void);
 static int sheevaplug_init(void);
 static int icebear_jtag_init(void);
 static int cortino_jtag_init(void);
+static int signalyzer_init(void);
 static int signalyzer_h_init(void);
 static int ktlink_init(void);
+static int redbee_init(void);
 
 /* reset procedures for supported layouts */
-static void usbjtag_reset(int trst, int srst);
+static void ftx23_reset(int trst, int srst);
 static void jtagkey_reset(int trst, int srst);
 static void olimex_jtag_reset(int trst, int srst);
 static void flyswatter_reset(int trst, int srst);
@@ -176,6 +201,7 @@ static void sheevaplug_reset(int trst, int srst);
 static void icebear_jtag_reset(int trst, int srst);
 static void signalyzer_h_reset(int trst, int srst);
 static void ktlink_reset(int trst, int srst);
+static void redbee_reset(int trst, int srst);
 
 /* blink procedures for layouts that support a blinking led */
 static void olimex_jtag_blink(void);
@@ -188,7 +214,7 @@ static const struct ft2232_layout  ft2232_layouts[] =
 {
        { .name = "usbjtag",
                .init = usbjtag_init,
-               .reset = usbjtag_reset,
+               .reset = ftx23_reset,
        },
        { .name = "jtagkey",
                .init = jtagkey_init,
@@ -203,16 +229,16 @@ static const struct ft2232_layout  ft2232_layouts[] =
                .reset = jtagkey_reset,
        },
        { .name = "signalyzer",
-               .init = usbjtag_init,
-               .reset = usbjtag_reset,
+               .init = signalyzer_init,
+               .reset = ftx23_reset,
        },
        { .name = "evb_lm3s811",
-               .init = usbjtag_init,
-               .reset = usbjtag_reset,
+               .init = lm3s811_jtag_init,
+               .reset = ftx23_reset,
        },
        { .name = "luminary_icdi",
-               .init = usbjtag_init,
-               .reset = usbjtag_reset,
+               .init = icdi_jtag_init,
+               .reset = ftx23_reset,
        },
        { .name = "olimex-jtag",
                .init = olimex_jtag_init,
@@ -263,15 +289,35 @@ static const struct ft2232_layout  ft2232_layouts[] =
                .reset = ktlink_reset,
                .blink = ktlink_blink
        },
+       { .name = "redbee-econotag",
+               .init = redbee_init,
+               .reset = redbee_reset,
+       },
+       { .name = "redbee-usb",
+               .init = redbee_init,
+               .reset = redbee_reset,
+               .channel = INTERFACE_B,
+       },
        { .name = NULL, /* END OF TABLE */ },
 };
 
-static uint8_t                  nTRST, nTRSTnOE, nSRST, nSRSTnOE;
+/* bitmask used to drive nTRST; usually a GPIOLx signal */
+static uint8_t                  nTRST;
+static uint8_t                  nTRSTnOE;
+/* bitmask used to drive nSRST; usually a GPIOLx signal */
+static uint8_t                  nSRST;
+static uint8_t                  nSRSTnOE;
 
+/** the layout being used with this debug session */
 static const struct ft2232_layout *layout;
+
+/** default bitmask values ddriven on DBUS: TCK/TDI/TDO/TMS and GPIOL(0..4) */
 static uint8_t                  low_output     = 0x0;
+/** default direction bitmask for DBUS: TCK/TDI/TDO/TMS and GPIOL(0..4) */
 static uint8_t                  low_direction  = 0x0;
+/** default value bitmask for CBUS GPIOH(0..4) */
 static uint8_t                  high_output    = 0x0;
+/** default direction bitmask for CBUS GPIOH(0..4) */
 static uint8_t                  high_direction = 0x0;
 
 #if BUILD_FT2232_FTD2XX == 1
@@ -1306,7 +1352,8 @@ static int ft2232_predict_scan_in(int scan_size, enum scan_type type)
        return predicted_size;
 }
 
-static void usbjtag_reset(int trst, int srst)
+/* semi-generic FT2232/FT4232 reset code */
+static void ftx23_reset(int trst, int srst)
 {
        enum reset_types jtag_reset_config = jtag_get_reset_config();
        if (trst == 1)
@@ -1577,6 +1624,36 @@ static void sheevaplug_reset(int trst, int srst)
        LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
 }
 
+static void redbee_reset(int trst, int srst)
+{
+       if (trst == 1)
+       {
+               tap_set_state(TAP_RESET);
+               high_output &= ~nTRST;
+       }
+       else if (trst == 0)
+       {
+               high_output |= nTRST;
+       }
+
+       if (srst == 1)
+       {
+               high_output &= ~nSRST;
+       }
+       else if (srst == 0)
+       {
+               high_output |= nSRST;
+       }
+
+       /* command "set data bits low byte" */
+       buffer_write(0x82);
+       buffer_write(high_output);
+       buffer_write(high_direction);
+       LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, "
+                       "high_direction: 0x%2.2x", trst, srst, high_output,
+                       high_direction);
+}
+
 static int ft2232_execute_runtest(struct jtag_command *cmd)
 {
        int retval;
@@ -1901,7 +1978,7 @@ static int ft2232_execute_command(struct jtag_command *cmd)
        {
        case JTAG_RESET:        retval = ft2232_execute_reset(cmd); break;
        case JTAG_RUNTEST:      retval = ft2232_execute_runtest(cmd); break;
-       case JTAG_STATEMOVE: retval = ft2232_execute_statemove(cmd); break;
+       case JTAG_TLR_RESET: retval = ft2232_execute_statemove(cmd); break;
        case JTAG_PATHMOVE:     retval = ft2232_execute_pathmove(cmd); break;
        case JTAG_SCAN:         retval = ft2232_execute_scan(cmd); break;
        case JTAG_SLEEP:        retval = ft2232_execute_sleep(cmd); break;
@@ -1969,7 +2046,12 @@ static int ft2232_init_ftd2xx(uint16_t vid, uint16_t pid, int more, int* try_mor
        char*   openex_string = NULL;
        uint8_t latency_timer;
 
-       LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", ft2232_layout, vid, pid);
+       if (layout == NULL) {
+               LOG_WARNING("No ft2232 layout specified'");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", layout->name, vid, pid);
 
 #if IS_WIN32 == 0
        /* Add non-standard Vid/Pid to the linux driver */
@@ -2136,8 +2218,13 @@ static int ft2232_init_libftdi(uint16_t vid, uint16_t pid, int more, int* try_mo
 {
        uint8_t latency_timer;
 
+       if (layout == NULL) {
+               LOG_WARNING("No ft2232 layout specified'");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
        LOG_DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)",
-                       ft2232_layout, vid, pid);
+                       layout->name, vid, pid);
 
        if (ftdi_init(&ftdic) < 0)
                return ERROR_JTAG_INIT_FAILED;
@@ -2217,8 +2304,6 @@ static int ft2232_init(void)
        uint8_t  buf[1];
        int retval;
        uint32_t bytes_written;
-       const struct ft2232_layout* cur_layout = ft2232_layouts;
-       int i;
 
        if (tap_get_tms_path_len(TAP_IRPAUSE,TAP_IRPAUSE) == 7)
        {
@@ -2229,29 +2314,12 @@ static int ft2232_init(void)
                LOG_DEBUG("ft2232 interface using shortest path jtag state transitions");
 
        }
-       if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
-       {
-               ft2232_layout = "usbjtag";
-               LOG_WARNING("No ft2232 layout specified, using default 'usbjtag'");
-       }
-
-       while (cur_layout->name)
-       {
-               if (strcmp(cur_layout->name, ft2232_layout) == 0)
-               {
-                       layout = cur_layout;
-                       break;
-               }
-               cur_layout++;
-       }
-
-       if (!layout)
-       {
-               LOG_ERROR("No matching layout found for %s", ft2232_layout);
+       if (layout == NULL) {
+               LOG_WARNING("No ft2232 layout specified'");
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       for (i = 0; 1; i++)
+       for (int i = 0; 1; i++)
        {
                /*
                 * "more indicates that there are more IDs to try, so we should
@@ -2270,7 +2338,7 @@ static int ft2232_init(void)
                                more, &try_more);
 #elif BUILD_FT2232_LIBFTDI == 1
                retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i],
-                                            more, &try_more, cur_layout->channel);
+                                            more, &try_more, layout->channel);
 #endif
                if (retval >= 0)
                        break;
@@ -2316,59 +2384,23 @@ static int ft2232_init(void)
        return ERROR_OK;
 }
 
-static int usbjtag_init(void)
+/** Updates defaults for DBUS signals:  the four JTAG signals
+ * (TCK, TDI, TDO, TMS) and * the four GPIOL signals.
+ */
+static inline void ftx232_init_head(void)
 {
-       uint8_t  buf[3];
-       uint32_t bytes_written;
-
        low_output    = 0x08;
        low_direction = 0x0b;
+}
 
-       if (strcmp(ft2232_layout, "usbjtag") == 0)
-       {
-               nTRST    = 0x10;
-               nTRSTnOE = 0x10;
-               nSRST    = 0x40;
-               nSRSTnOE = 0x40;
-       }
-       else if (strcmp(ft2232_layout, "signalyzer") == 0)
-       {
-               nTRST    = 0x10;
-               nTRSTnOE = 0x10;
-               nSRST    = 0x20;
-               nSRSTnOE = 0x20;
-       }
-       else if (strcmp(ft2232_layout, "evb_lm3s811") == 0)
-       {
-               /* There are multiple revisions of LM3S811 eval boards:
-                * - Rev B (and older?) boards have no SWO trace support.
-                * - Rev C boards add ADBUS_6 DBG_ENn and BDBUS_4 SWO_EN;
-                *   they should use the "luminary_icdi" layout instead.
-                */
-               nTRST = 0x0;
-               nTRSTnOE = 0x00;
-               nSRST = 0x20;
-               nSRSTnOE = 0x20;
-               low_output    = 0x88;
-               low_direction = 0x8b;
-       }
-       else if (strcmp(ft2232_layout, "luminary_icdi") == 0)
-       {
-               /* Most Luminary eval boards support SWO trace output,
-                * and should use this "luminary_icdi" layout.
-                */
-               nTRST = 0x0;
-               nTRSTnOE = 0x00;
-               nSRST = 0x20;
-               nSRSTnOE = 0x20;
-               low_output    = 0x88;
-               low_direction = 0xcb;
-       }
-       else
-       {
-               LOG_ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout);
-               return ERROR_JTAG_INIT_FAILED;
-       }
+/** Initializes DBUS signals:  the four JTAG signals (TCK, TDI, TDO, TMS),
+ * the four GPIOL signals.  Initialization covers value and direction,
+ * as customized for each layout.
+ */
+static int ftx232_init_tail(void)
+{
+       uint8_t  buf[3];
+       uint32_t bytes_written;
 
        enum reset_types jtag_reset_config = jtag_get_reset_config();
        if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
@@ -2401,13 +2433,76 @@ static int usbjtag_init(void)
 
        if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
        {
-               LOG_ERROR("couldn't initialize FT2232 with 'USBJTAG' layout");
+               LOG_ERROR("couldn't initialize FT2232 DBUS");
                return ERROR_JTAG_INIT_FAILED;
        }
 
        return ERROR_OK;
 }
 
+static int usbjtag_init(void)
+{
+       /*
+        * NOTE:  This is now _specific_ to the "usbjtag" layout.
+        * Don't try cram any more layouts into this.
+        */
+       ftx232_init_head();
+
+       nTRST    = 0x10;
+       nTRSTnOE = 0x10;
+       nSRST    = 0x40;
+       nSRSTnOE = 0x40;
+
+       return ftx232_init_tail();
+}
+
+static int lm3s811_jtag_init(void)
+{
+       ftx232_init_head();
+
+       /* There are multiple revisions of LM3S811 eval boards:
+        * - Rev B (and older?) boards have no SWO trace support.
+        * - Rev C boards add ADBUS_6 DBG_ENn and BDBUS_4 SWO_EN;
+        *   they should use the "luminary_icdi" layout instead.
+        */
+       nTRST = 0x0;
+       nTRSTnOE = 0x00;
+       nSRST = 0x20;
+       nSRSTnOE = 0x20;
+       low_output    = 0x88;
+       low_direction = 0x8b;
+
+       return ftx232_init_tail();
+}
+
+static int icdi_jtag_init(void)
+{
+       ftx232_init_head();
+
+       /* Most Luminary eval boards support SWO trace output,
+        * and should use this "luminary_icdi" layout.
+        */
+       nTRST = 0x0;
+       nTRSTnOE = 0x00;
+       nSRST = 0x20;
+       nSRSTnOE = 0x20;
+       low_output    = 0x88;
+       low_direction = 0xcb;
+
+       return ftx232_init_tail();
+}
+
+static int signalyzer_init(void)
+{
+       ftx232_init_head();
+
+       nTRST    = 0x10;
+       nTRSTnOE = 0x10;
+       nSRST    = 0x20;
+       nSRSTnOE = 0x20;
+       return ftx232_init_tail();
+}
+
 static int axm0432_jtag_init(void)
 {
        uint8_t  buf[3];
@@ -2478,6 +2573,73 @@ static int axm0432_jtag_init(void)
        return ERROR_OK;
 }
 
+static int redbee_init(void)
+{
+       uint8_t  buf[3];
+       uint32_t bytes_written;
+
+       low_output    = 0x08;
+       low_direction = 0x2b;
+
+       /* initialize low byte for jtag */
+       /* command "set data bits low byte" */
+       buf[0] = 0x80;
+       /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */
+       buf[2] = low_direction;
+       /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */
+       buf[1] = low_output;
+       LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK)
+                       || (bytes_written != 3))
+       {
+               LOG_ERROR("couldn't initialize FT2232 with 'redbee' layout");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       nTRST    = 0x08;
+       nTRSTnOE = 0x0;     /* No output enable for TRST*/
+       nSRST    = 0x04;
+       nSRSTnOE = 0x0;     /* No output enable for SRST*/
+
+       high_output    = 0x0;
+       high_direction = 0x0c;
+
+       enum reset_types jtag_reset_config = jtag_get_reset_config();
+       if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+       {
+               LOG_ERROR("can't set nTRSTOE to push-pull on redbee");
+       }
+       else
+       {
+               high_output |= nTRST;
+       }
+
+       if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+       {
+               LOG_ERROR("can't set nSRST to push-pull on redbee");
+       }
+       else
+       {
+               high_output |= nSRST;
+       }
+
+       /* initialize high port */
+       buf[0] = 0x82;              /* command "set data bits high byte" */
+       buf[1] = high_output;       /* value */
+       buf[2] = high_direction;    /* all outputs (xRST and xRSTnOE) */
+       LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+       if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK)
+                       || (bytes_written != 3))
+       {
+               LOG_ERROR("couldn't initialize FT2232 with 'redbee' layout");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
 static int jtagkey_init(void)
 {
        uint8_t  buf[3];
@@ -3013,13 +3175,28 @@ COMMAND_HANDLER(ft2232_handle_serial_command)
 
 COMMAND_HANDLER(ft2232_handle_layout_command)
 {
-       if (CMD_ARGC == 0)
-               return ERROR_OK;
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Need exactly one argument to ft2232_layout");
+               return ERROR_FAIL;
+       }
 
-       ft2232_layout = malloc(strlen(CMD_ARGV[0]) + 1);
-       strcpy(ft2232_layout, CMD_ARGV[0]);
+       if (layout) {
+               LOG_ERROR("already specified ft2232_layout %s",
+                               layout->name);
+               return (strcmp(layout->name, CMD_ARGV[0]) != 0)
+                               ? ERROR_FAIL
+                               : ERROR_OK;
+       }
 
-       return ERROR_OK;
+       for (const struct ft2232_layout *l = ft2232_layouts; l->name; l++) {
+               if (strcmp(l->name, CMD_ARGV[0]) == 0) {
+                       layout = l;
+                       return ERROR_OK;
+               }
+       }
+
+       LOG_ERROR("No FT2232 layout '%s' found", CMD_ARGV[0]);
+       return ERROR_FAIL;
 }
 
 COMMAND_HANDLER(ft2232_handle_vid_pid_command)