This is an automated email from Gerrit.

"Tim Newsome <t...@sifive.com>" just uploaded a new patch set to Gerrit, which 
you can find at https://review.openocd.org/c/openocd/+/6981

-- gerrit

commit 808d8d56139e343537d64771c1d7fe175018420f
Author: Tim Newsome <t...@sifive.com>
Date:   Mon May 16 14:02:30 2022 -0700

    Support two-wire cJTAG OSCAN1 using FTDI adapters
    
    cJTAG OSCAN1, in lieu of 4-wire JTAG, is starting to be a configuration
    option for some SiFive hardware. An FTDI-based adapter that can be
    configured to drive the bidirectional pin TMSC is assumed for this
    topology. Specifically, the Olimex ARM-USB-TINY-H with the ARM-JTAG-SWD
    adapter, connected to a SiFive cJTAG-enabled target board is the only
    known concrete topology, currently. But in theory, other FTDI based
    devices that can drive a two-wire bidirectional signaling pattern could
    be made to work in this scheme in the future.
    
    These code changes are offered as a way to drive that topology. It's
    translating IR/DR and JTAG traversal commands to the two-wire clocking
    and signaling.
    
    See https://github.com/riscv/riscv-openocd/pull/320
    
    Signed-off-by: Tim Newsome <t...@sifive.com>
    Change-Id: Ia1daa2c01227c4b0005be947b2bb0de81a800874

diff --git a/configure.ac b/configure.ac
index 95b2d50ae1..60d1ed674d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -110,6 +110,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], 
[-])])
 
 m4_define([USB1_ADAPTERS],
        [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
+       [[ftdi_oscan1], [cJTAG OSCAN1 tunneled thru MPSSE], [FTDI_OSCAN1]],
        [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]],
        [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
        [[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
diff --git a/doc/openocd.texi b/doc/openocd.texi
index be9e5ac085..c1839c6da6 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -2594,6 +2594,13 @@ minimal impact on the target system. Avoid floating 
inputs, conflicting outputs
 and initially asserted reset signals.
 @end deffn
 
+@deffn {Command} {ftdi oscan1_mode} on|off
+Enable or disable OSCAN1 mode. This mode is intended for use with an adapter,
+such as the ARM-JTAG-SWD by Olimex, that sits in between the FTDI chip and the
+target. The adapter uses the normal JTAG signals to control TCKC and TMSC
+(bidirectional) signals used in 2-wire cJTAG.
+@end deffn
+
 @deffn {Command} {ftdi layout_signal} name [@option{-data}|@option{-ndata} 
data_mask] [@option{-input}|@option{-ninput} input_mask] 
[@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name]
 Creates a signal with the specified @var{name}, controlled by one or more FTDI
 GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 7671cee5d0..2ecff7f862 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -85,6 +85,16 @@
 /* FTDI access library includes */
 #include "mpsse.h"
 
+#if BUILD_FTDI_OSCAN1 == 1
+#define DO_CLOCK_DATA clock_data
+#define DO_CLOCK_TMS_CS clock_tms_cs
+#define DO_CLOCK_TMS_CS_OUT clock_tms_cs_out
+#else
+#define DO_CLOCK_DATA mpsse_clock_data
+#define DO_CLOCK_TMS_CS mpsse_clock_tms_cs
+#define DO_CLOCK_TMS_CS_OUT mpsse_clock_tms_cs_out
+#endif
+
 #define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
 #define JTAG_MODE_ALT (LSB_FIRST | NEG_EDGE_IN | NEG_EDGE_OUT)
 #define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
@@ -95,6 +105,31 @@ static uint8_t ftdi_jtag_mode = JTAG_MODE;
 
 static bool swd_mode;
 
+#if BUILD_FTDI_OSCAN1 == 1
+/*
+  The cJTAG 2-wire OSCAN1 protocol, in lieu of 4-wire JTAG, is a configuration 
option
+  for some SoCs. An FTDI-based adapter that can be configured to appropriately 
drive
+  the bidirectional pin TMSC is able to drive OSCAN1 protocol.  For example, 
an Olimex
+  ARM-USB-TINY-H with the ARM-JTAG-SWD adapter, connected to a cJTAG-enabled
+  target board is such a topology.  A TCK cycle with TMS=1/TDI=N translates to 
a TMSC
+  output of N, and a TCK cycle with TMS=0 translates to a TMSC input from the 
target back
+  to the adapter/probe.  The OSCAN1 protocol uses 3 TCK cycles to generate the 
data flow
+  that is equivalent to that of a single TCK cycle in 4-wire JTAG. The 
OSCAN1-related
+  code in this module translates IR/DR scan commanads and JTAG state traversal 
commands
+  to the two-wire clocking and signaling of OSCAN1 protocol, if placed into 
oscan1 mode
+  during initialization.
+*/
+static void oscan1_reset_online_activate(void);
+static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, 
unsigned out_offset, uint8_t *in,
+                                   unsigned in_offset, unsigned length, 
uint8_t mode);
+static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t 
*out, unsigned out_offset, uint8_t *in,
+                                     unsigned in_offset, unsigned length, bool 
tdi, uint8_t mode);
+static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t 
*out, unsigned out_offset,
+                                         unsigned length, bool tdi, uint8_t 
mode);
+
+static bool oscan1_mode;
+#endif
+
 #define MAX_USB_IDS 8
 /* vid = pid = 0 marks the end of the list */
 static uint16_t ftdi_vid[MAX_USB_IDS + 1] = { 0 };
@@ -240,6 +275,35 @@ static int ftdi_get_signal(const struct signal *s, 
uint16_t *value_out)
        return ERROR_OK;
 }
 
+#if BUILD_FTDI_OSCAN1 == 1
+static void clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned 
out_offset, uint8_t *in,
+                    unsigned in_offset, unsigned length, uint8_t mode)
+{
+       if (oscan1_mode)
+               oscan1_mpsse_clock_data(ctx, out, out_offset, in, in_offset, 
length, mode);
+       else
+               mpsse_clock_data(ctx, out, out_offset, in, in_offset, length, 
mode);
+}
+
+static void clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned 
out_offset, uint8_t *in,
+                      unsigned in_offset, unsigned length, bool tdi, uint8_t 
mode)
+{
+       if (oscan1_mode)
+               oscan1_mpsse_clock_tms_cs(ctx, out, out_offset, in, in_offset, 
length, tdi, mode);
+       else
+               mpsse_clock_tms_cs(ctx, out, out_offset, in, in_offset, length, 
tdi, mode);
+}
+
+static void clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, 
unsigned out_offset,
+                          unsigned length, bool tdi, uint8_t mode)
+{
+       if (oscan1_mode)
+               oscan1_mpsse_clock_tms_cs_out(ctx, out, out_offset, length, 
tdi, mode);
+       else
+               mpsse_clock_tms_cs_out(ctx, out, out_offset, length, tdi, mode);
+}
+#endif
+
 /**
  * Function move_to_state
  * moves the TAP controller from the current state to a
@@ -268,7 +332,7 @@ static void move_to_state(tap_state_t goal_state)
        for (int i = 0; i < tms_count; i++)
                tap_set_state(tap_state_transition(tap_get_state(), (tms_bits 
>> i) & 1));
 
-       mpsse_clock_tms_cs_out(mpsse_ctx,
+       DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
                &tms_bits,
                0,
                tms_count,
@@ -322,7 +386,7 @@ static void ftdi_end_state(tap_state_t state)
 static void ftdi_execute_runtest(struct jtag_command *cmd)
 {
        int i;
-       uint8_t zero = 0;
+       static const uint8_t zero;
 
        LOG_DEBUG_IO("runtest %i cycles, end in %s",
                cmd->cmd.runtest->num_cycles,
@@ -336,7 +400,7 @@ static void ftdi_execute_runtest(struct jtag_command *cmd)
        while (i > 0) {
                /* there are no state transitions in this code, so omit state 
tracking */
                unsigned this_len = i > 7 ? 7 : i;
-               mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, 
ftdi_jtag_mode);
+               DO_CLOCK_TMS_CS_OUT(mpsse_ctx, &zero, 0, this_len, false, 
ftdi_jtag_mode);
                i -= this_len;
        }
 
@@ -371,7 +435,7 @@ static void ftdi_execute_tms(struct jtag_command *cmd)
        LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
 
        /* TODO: Missing tap state tracking, also missing from ft2232.c! */
-       mpsse_clock_tms_cs_out(mpsse_ctx,
+       DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
                cmd->cmd.tms->bits,
                0,
                cmd->cmd.tms->num_bits,
@@ -418,7 +482,7 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
                state_count++;
 
                if (bit_count == 7 || num_states == 0) {
-                       mpsse_clock_tms_cs_out(mpsse_ctx,
+                       DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
                                        &tms_byte,
                                        0,
                                        bit_count,
@@ -472,7 +536,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != 
tap_get_end_state()) {
                        /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock 
last bit during tap
                         * movement. This last field can't have length zero, it 
was checked above. */
-                       mpsse_clock_data(mpsse_ctx,
+                       DO_CLOCK_DATA(mpsse_ctx,
                                field->out_value,
                                0,
                                field->in_value,
@@ -482,12 +546,8 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                        uint8_t last_bit = 0;
                        if (field->out_value)
                                bit_copy(&last_bit, 0, field->out_value, 
field->num_bits - 1, 1);
-
-                       /* If endstate is TAP_IDLE, clock out 1-1-0 (->EXIT1 
->UPDATE ->IDLE)
-                        * Otherwise, clock out 1-0 (->EXIT1 ->PAUSE)
-                        */
                        uint8_t tms_bits = 0x03;
-                       mpsse_clock_tms_cs(mpsse_ctx,
+                       DO_CLOCK_TMS_CS(mpsse_ctx,
                                        &tms_bits,
                                        0,
                                        field->in_value,
@@ -497,7 +557,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                        ftdi_jtag_mode);
                        tap_set_state(tap_state_transition(tap_get_state(), 1));
                        if (tap_get_end_state() == TAP_IDLE) {
-                               mpsse_clock_tms_cs_out(mpsse_ctx,
+                               DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
                                                &tms_bits,
                                                1,
                                                2,
@@ -506,7 +566,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                
tap_set_state(tap_state_transition(tap_get_state(), 1));
                                
tap_set_state(tap_state_transition(tap_get_state(), 0));
                        } else {
-                               mpsse_clock_tms_cs_out(mpsse_ctx,
+                               DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
                                                &tms_bits,
                                                2,
                                                1,
@@ -515,7 +575,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                
tap_set_state(tap_state_transition(tap_get_state(), 0));
                        }
                } else
-                       mpsse_clock_data(mpsse_ctx,
+                       DO_CLOCK_DATA(mpsse_ctx,
                                field->out_value,
                                0,
                                field->in_value,
@@ -596,7 +656,7 @@ static void ftdi_execute_stableclocks(struct jtag_command 
*cmd)
        while (num_cycles > 0) {
                /* there are no state transitions in this code, so omit state 
tracking */
                unsigned this_len = num_cycles > 7 ? 7 : num_cycles;
-               mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, 
ftdi_jtag_mode);
+               DO_CLOCK_TMS_CS_OUT(mpsse_ctx, &tms, 0, this_len, false, 
ftdi_jtag_mode);
                num_cycles -= this_len;
        }
 
@@ -608,11 +668,19 @@ static void ftdi_execute_stableclocks(struct jtag_command 
*cmd)
 static void ftdi_execute_command(struct jtag_command *cmd)
 {
        switch (cmd->type) {
+               case JTAG_RESET:
+#if BUILD_FTDI_OSCAN1 == 1
+                       oscan1_reset_online_activate(); /* put the target back 
into OSCAN1 mode */
+#endif
+                       break;
                case JTAG_RUNTEST:
                        ftdi_execute_runtest(cmd);
                        break;
                case JTAG_TLR_RESET:
                        ftdi_execute_statemove(cmd);
+#if BUILD_FTDI_OSCAN1 == 1
+                       oscan1_reset_online_activate(); /* put the target back 
into OSCAN1 mode */
+#endif
                        break;
                case JTAG_PATHMOVE:
                        ftdi_execute_pathmove(cmd);
@@ -691,6 +759,17 @@ static int ftdi_initialize(void)
                /* A dummy SWD_EN would have zero mask */
                if (sig->data_mask)
                        ftdi_set_signal(sig, '1');
+#if BUILD_FTDI_OSCAN1 == 1
+       } else if (oscan1_mode) {
+               struct signal *sig = find_signal_by_name("JTAG_SEL");
+               if (!sig) {
+                       LOG_ERROR("OSCAN1 mode is active but JTAG_SEL signal is 
not defined");
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+               /* A dummy JTAG_SEL would have zero mask */
+               if (sig->data_mask)
+                       ftdi_set_signal(sig, '0');
+#endif
        }
 
        mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 
0xff);
@@ -722,6 +801,254 @@ static int ftdi_quit(void)
        return ERROR_OK;
 }
 
+#if BUILD_FTDI_OSCAN1 == 1
+static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, 
unsigned out_offset, uint8_t *in,
+                    unsigned in_offset, unsigned length, uint8_t mode)
+{
+       static const uint8_t zero;
+       static const uint8_t one = 1;
+
+       LOG_DEBUG_IO("oscan1_mpsse_clock_data: %sout %d bits", in ? "in" : "", 
length);
+
+       for (unsigned i = 0; i < length; i++) {
+               int bitnum;
+               uint8_t bit;
+
+               /* OSCAN1 uses 3 separate clocks */
+
+               /* drive TMSC to the *negation* of the desired TDI value */
+               bitnum = out_offset + i;
+               bit = out ? ((out[bitnum/8] >> (bitnum%8)) & 0x1) : 0;
+
+               /* Try optimized case first: if desired TDI bit is 1, then we
+                  can fuse what would otherwise be the first two MPSSE 
commands */
+               if (bit) {
+                       const uint8_t tmsbits = 0x3;  /* 1, 1 */
+                       mpsse_clock_tms_cs_out(mpsse_ctx, &tmsbits, 0, 2, 
false, mode);
+               } else {
+                       /* Can't fuse because TDI varies; less efficient */
+                       mpsse_clock_tms_cs_out(mpsse_ctx, &one, 0, 1, bit ? 0 : 
1, mode);
+
+                       /* drive TMSC to desired TMS value (always zero in this 
context) */
+                       mpsse_clock_tms_cs_out(mpsse_ctx, &one, 0, 1, false, 
mode);
+               }
+
+               /* drive another TCK without driving TMSC (TDO cycle) */
+               mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset+i, 1, 
false, mode);
+       }
+}
+
+
+static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t 
*out, unsigned out_offset, uint8_t *in,
+                      unsigned in_offset, unsigned length, bool tdi, uint8_t 
mode)
+{
+       static const uint8_t zero;
+       static const uint8_t one = 1;
+
+       LOG_DEBUG_IO("oscan1_mpsse_clock_tms_cs: %sout %d bits, tdi=%d", in ? 
"in" : "", length, tdi);
+
+       for (unsigned i = 0; i < length; i++) {
+               int bitnum;
+               uint8_t tmsbit;
+               uint8_t tdibit;
+
+               /* OSCAN1 uses 3 separate clocks */
+
+               /* drive TMSC to the *negation* of the desired TDI value */
+               tdibit = tdi ? 0 : 1;
+
+               /* drive TMSC to desired TMS value */
+               bitnum = out_offset + i;
+               tmsbit = ((out[bitnum/8] >> (bitnum%8)) & 0x1);
+
+               if (tdibit == tmsbit) {
+                       /* Can squash into a single MPSSE command */
+                       const uint8_t tmsbits = 0x3;
+                       mpsse_clock_tms_cs_out(mpsse_ctx, &tmsbits, 0, 2, 
tdibit, mode);
+               } else {
+                       /* Unoptimized case, can't formulate with a single 
command */
+                       mpsse_clock_tms_cs_out(mpsse_ctx, &one, 0, 1, tdibit, 
mode);
+                       mpsse_clock_tms_cs_out(mpsse_ctx, &one, 0, 1, (tmsbit 
!= 0), mode);
+               }
+
+               /* drive another TCK without driving TMSC (TDO cycle) */
+               mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset+i, 1, 
false, mode);
+       }
+}
+
+
+static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t 
*out, unsigned out_offset,
+                          unsigned length, bool tdi, uint8_t mode)
+{
+       oscan1_mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, 
mode);
+}
+
+
+static void oscan1_set_tck_tms_tdi(struct signal *tck, char tckvalue, struct 
signal *tms,
+                                  char tmsvalue, struct signal *tdi, char 
tdivalue)
+{
+       ftdi_set_signal(tms, tmsvalue);
+       ftdi_set_signal(tdi, tdivalue);
+       ftdi_set_signal(tck, tckvalue);
+}
+
+static void oscan1_reset_online_activate(void)
+{
+       /* After TAP reset, the OSCAN1-to-JTAG adapter is in offline and
+       non-activated state.  Escape sequences are needed to bring
+       the TAP online and activated into OSCAN1 mode. */
+
+       struct signal *tck = find_signal_by_name("TCK");
+       struct signal *tdi = find_signal_by_name("TDI");
+       struct signal *tms = find_signal_by_name("TMS");
+       struct signal *tdo = find_signal_by_name("TDO");
+       uint16_t tdovalue;
+
+       static const struct {
+         int8_t tck;
+         int8_t tms;
+         int8_t tdi;
+       } sequence[] = {
+         /* TCK=0, TMS=1, TDI=0 (drive TMSC to 0 baseline) */
+         {'0', '1', '0'},
+
+         /* Drive cJTAG escape sequence for TAP reset - 8 TMSC edges */
+         /* TCK=1, TMS=1, TDI=0 (rising edge of TCK with TMSC still 0) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */
+         {'0', '1', '0'},
+
+         /* 3 TCK pulses for padding */
+         /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (drive rising TCK edge) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (drive falling TCK edge) */
+         {'0', '1', '0'},
+
+         /* Drive cJTAG escape sequence for SELECT */
+         /* TCK=1, TMS=1, TDI=0 (rising edge of TCK with TMSC still 0, TAP 
reset that was just setup occurs here too) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=1, TMS=1, TDI=1 (drive rising TMSC edge) */
+         {'1', '1', '1'},
+         /* TCK=1, TMS=1, TDI=0 (drive falling TMSC edge) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK with TMSC still 0) */
+         {'0', '1', '0'},
+
+         /* Drive cJTAG escape sequence for activation */
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK with TMSC still 0... online 
mode activated... also OAC bit0==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... OAC bit1==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=1 (falling edge TCK) */
+         {'0', '1', '1'},
+         /* TCK=1, TMS=1, TDI=1 (rising edge TCK... OAC bit2==1) */
+         {'1', '1', '1'},
+         /* TCK=0, TMS=1, TDI=1 (falling edge TCK, TMSC stays high) */
+         {'0', '1', '1'},
+         /* TCK=1, TMS=1, TDI=1 (rising edge TCK... OAC bit3==1) */
+         {'1', '1', '1'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit0==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit1==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... EC bit2==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=1 (falling edge TCK) */
+         {'0', '1', '1'},
+         /* TCK=1, TMS=1, TDI=1 (rising edge TCK... EC bit3==1) */
+         {'1', '1', '1'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit0==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit1==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit2==0) */
+         {'1', '1', '0'},
+         /* TCK=0, TMS=1, TDI=0 (falling edge TCK) */
+         {'0', '1', '0'},
+         /* TCK=1, TMS=1, TDI=0 (rising edge TCK... CP bit3==0) */
+         {'1', '1', '0'},
+       };
+
+
+       if (!oscan1_mode)
+               return;
+
+
+       if (!tck) {
+               LOG_ERROR("Can't run cJTAG online/activate escape sequences: 
TCK signal is not defined");
+               return;
+       }
+
+       if (!tdi) {
+               LOG_ERROR("Can't run cJTAG online/activate escape sequences: 
TDI signal is not defined");
+               return;
+       }
+
+       if (!tms) {
+               LOG_ERROR("Can't run cJTAG online/activate escape sequences: 
TMS signal is not defined");
+               return;
+       }
+
+       if (!tdo) {
+               LOG_ERROR("Can't run cJTAG online/activate escape sequences: 
TDO signal is not defined");
+               return;
+       }
+
+       /* Send the sequence to the adapter */
+       for (size_t i = 0; i < sizeof(sequence)/sizeof(sequence[0]); i++)
+               oscan1_set_tck_tms_tdi(tck, sequence[i].tck, tms, 
sequence[i].tms, tdi, sequence[i].tdi);
+
+       ftdi_get_signal(tdo, &tdovalue);  /* Just to force a flush */
+}
+
+#endif /* #if BUILD_FTDI_OSCAN1 == 1 */
+
 COMMAND_HANDLER(ftdi_handle_device_desc_command)
 {
        if (CMD_ARGC == 1) {
@@ -933,6 +1260,20 @@ COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command)
        return ERROR_OK;
 }
 
+#if BUILD_FTDI_OSCAN1 == 1
+COMMAND_HANDLER(ftdi_handle_oscan1_mode_command)
+{
+       if (CMD_ARGC > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_ON_OFF(CMD_ARGV[0], oscan1_mode);
+
+       command_print(CMD, "oscan1 mode: %s.", oscan1_mode ? "on" : "off");
+       return ERROR_OK;
+}
+#endif
+
 static const struct command_registration ftdi_subcommand_handlers[] = {
        {
                .name = "device_desc",
@@ -994,6 +1335,15 @@ static const struct command_registration 
ftdi_subcommand_handlers[] = {
                        "allow signalling speed increase)",
                .usage = "(rising|falling)",
        },
+#if BUILD_FTDI_OSCAN1 == 1
+       {
+               .name = "oscan1_mode",
+               .handler = &ftdi_handle_oscan1_mode_command,
+               .mode = COMMAND_ANY,
+               .help = "set to 'on' to use OSCAN1 mode for signaling, 
otherwise 'off' (default is 'off')",
+               .usage = "(on|off)",
+       },
+#endif
        COMMAND_REGISTRATION_DONE
 };
 
diff --git a/tcl/interface/ftdi/olimex-arm-jtag-cjtag.cfg 
b/tcl/interface/ftdi/olimex-arm-jtag-cjtag.cfg
new file mode 100644
index 0000000000..6939d00267
--- /dev/null
+++ b/tcl/interface/ftdi/olimex-arm-jtag-cjtag.cfg
@@ -0,0 +1,27 @@
+#
+# Olimex ARM JTAG SWD adapter
+# https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-SWD/
+#
+
+#
+# Olimex ARM-USB-TINY-H
+#
+# http://www.olimex.com/dev/arm-usb-tiny-h.html
+#
+
+interface ftdi
+ftdi oscan1_mode on
+ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H"
+ftdi vid_pid 0x15ba 0x002a
+
+ftdi layout_init 0x0808 0x0a1b
+ftdi layout_signal nSRST -oe 0x0200
+# oscan1_ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100
+ftdi layout_signal LED -data 0x0800
+
+# These signals are used for cJTAG escape sequence on initialization only
+ftdi layout_signal TCK -data 0x0001
+ftdi layout_signal TDI -data 0x0002
+ftdi layout_signal TDO -input 0x0004
+ftdi layout_signal TMS -data 0x0008
+ftdi layout_signal JTAG_SEL -data 0x0100 -oe 0x0100
diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg 
b/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg
new file mode 100644
index 0000000000..36ac587620
--- /dev/null
+++ b/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg
@@ -0,0 +1,22 @@
+#
+# Olimex ARM-USB-OCD-H (using cJTAG)
+#
+# http://www.olimex.com/dev/arm-usb-ocd-h.html
+#
+
+interface ftdi
+ftdi oscan1_mode on
+ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H"
+ftdi vid_pid 0x15ba 0x002b
+
+ftdi layout_init 0x0808 0x0a1b
+ftdi layout_signal nSRST -oe 0x0200
+# oscan1_ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100
+ftdi layout_signal LED -data 0x0800
+
+# These signals are used for cJTAG escape sequence on initialization only
+ftdi layout_signal TCK -data 0x0001
+ftdi layout_signal TDI -data 0x0002
+ftdi layout_signal TDO -input 0x0004
+ftdi layout_signal TMS -data 0x0008
+ftdi layout_signal JTAG_SEL -data 0x0100 -oe 0x0100
diff --git a/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.cfg 
b/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.cfg
new file mode 100644
index 0000000000..13378b394a
--- /dev/null
+++ b/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.cfg
@@ -0,0 +1,27 @@
+#
+# Olimex ARM JTAG SWD adapter
+# https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-SWD/
+#
+
+#
+# Olimex ARM-USB-TINY-H (using cJTAG)
+#
+# http://www.olimex.com/dev/arm-usb-tiny-h.html
+#
+
+interface ftdi
+ftdi oscan1_mode on
+ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H"
+ftdi vid_pid 0x15ba 0x002a
+
+ftdi layout_init 0x0808 0x0a1b
+ftdi layout_signal nSRST -oe 0x0200
+# oscan1_ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100
+ftdi layout_signal LED -data 0x0800
+
+# These signals are used for cJTAG escape sequence on initialization only
+ftdi layout_signal TCK -data 0x0001
+ftdi layout_signal TDI -data 0x0002
+ftdi layout_signal TDO -input 0x0004
+ftdi layout_signal TMS -data 0x0008
+ftdi layout_signal JTAG_SEL -data 0x0100 -oe 0x0100

-- 

Reply via email to