This is an automated email from Gerrit.

"ZhiYuanNJ <871238...@qq.com>" just uploaded a new patch set to Gerrit, which 
you can find at https://review.openocd.org/c/openocd/+/8612

-- gerrit

commit 27b3defa48d1bb52103fe9322c113caec7b9b92b
Author: Henrik Mau <henrik....@analog.com>
Date:   Wed Nov 13 15:43:23 2024 +0000

    jtag/drivers: Add support for WCH CH347T/F interfaces
    
    CH347 is a high-speed USB bus converter chip.
    Can provides JTAG/SWD/UART/SPI/I2C interface through USB bus.
    This driver comes from:
    https://github.com/WCHSoftGroup/ch347
    
    Change-Id: Id19b6ba270f8bd19943dde3bbd986c99553b82c8
    Signed-off-by: ZhiYuanNJ <871238...@qq.com>

diff --git a/configure.ac b/configure.ac
index 567152b0a6..8feec92b06 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,6 +121,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], 
[-])])
 
 m4_define([USB1_ADAPTERS],
        [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
+       [[ch347], [Mode 3 of CH347 based devices], [CH347]],
        [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]],
        [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
        [[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
@@ -405,6 +406,10 @@ AC_ARG_ENABLE([remote-bitbang],
   AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the 
Remote Bitbang driver]),
   [build_remote_bitbang=$enableval], [build_remote_bitbang=no])
 
+AC_ARG_ENABLE([ch347],
+  AS_HELP_STRING([--enable-ch347], [Enable building support for CH347]),
+  [build_ch347=$enableval], [build_ch347=no])
+
 AS_CASE(["${host_cpu}"],
   [i?86|x86*], [],
   [
@@ -632,6 +637,12 @@ AS_IF([test "x$build_sysfsgpio" = "xyes"], [
   AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.])
 ])
 
+AS_IF([test "x$build_ch347" = "xyes"], [
+  AC_DEFINE([BUILD_CH347], [1], [1 if you want CH347.])
+], [
+  AC_DEFINE([BUILD_CH347], [0], [0 if you don't want CH347.])
+])
+
 PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [
        use_libusb1=yes
        AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x])
@@ -795,6 +806,7 @@ AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = 
"xyes"])
 AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"])
 AM_CONDITIONAL([DMEM], [test "x$build_dmem" = "xyes"])
 AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"])
+AM_CONDITIONAL([BUILD_CH347], [test "x$build_ch347" = "xyes"])
 
 AM_CONDITIONAL([INTERNAL_JIMTCL], [test "x$use_internal_jimtcl" = "xyes"])
 AM_CONDITIONAL([HAVE_JIMTCL_PKG_CONFIG], [test "x$have_jimtcl_pkg_config" = 
"xyes"])
diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules
index 29f8d7a6d4..5ff0dc22be 100644
--- a/contrib/60-openocd.rules
+++ b/contrib/60-openocd.rules
@@ -216,6 +216,10 @@ ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", 
MODE="660", GROUP="plugdev",
 # USBprog with OpenOCD firmware
 ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", 
GROUP="plugdev", TAG+="uaccess"
 
+# WCH CH347 chip
+ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55dd", MODE="660", 
GROUP="plugdev", TAG+="uaccess"
+ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55de", MODE="660", 
GROUP="plugdev", TAG+="uaccess"
+
 # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
 ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", 
GROUP="plugdev", TAG+="uaccess"
 
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 9b5cfbb83e..a3bed045c3 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -624,6 +624,9 @@ This is deprecated from Linux v5.3; prefer using 
@b{linuxgpiod}.
 @item @b{esp_usb_jtag}
 @* A JTAG driver to communicate with builtin debug modules of Espressif 
ESP32-C3 and ESP32-S3 chips using OpenOCD.
 
+@item @b{ch347T/F}
+@* A JTAG driver which uses the WCH CH347T/F JTAG chip.
+
 @end itemize
 
 @node About Jim-Tcl
diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c
new file mode 100644
index 0000000000..eb003fa711
--- /dev/null
+++ b/src/jtag/drivers/ch347.c
@@ -0,0 +1,1515 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Driver for CH347-JTAG interface V1.1                                  *
+ *                                                                         *
+ *   Copyright (C) 2024 by oidcat <oidcat...@163.com>                      *
+ *                                                                         *
+ *   CH347 is a high-speed USB bus converter chip that provides UART, I2C  *
+ *   and SPI synchronous serial ports and JTAG interface through USB bus.  *
+ *                                                                         *
+ *   The Jtag interface by CH347 can supports transmission frequency       *
+ *   configuration up to 60MHz.                                            *
+ *                                                                         *
+ *   The USB2.0 to JTAG scheme based on CH347 can be used to build         *
+ *   customized USB high-speed JTAG debugger and other products.           *
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ *            _____________                                                *
+ *           |             |____JTAG/SWD (TDO,TDI,TMS,TCK,TRST)            *
+ *      USB__|   CH347T/F  |                                               *
+ *           |_____________|____UART(TXD1,RXD1,RTS1,CTS1,DTR1)             *
+ *            ______|______                                                *
+ *           |             |                                               *
+ *           | 8 MHz XTAL  |                                               *
+ *           |_____________|                                               *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if IS_CYGWIN == 1
+#include "windows.h"
+#undef LOG_ERROR
+#endif
+/* project specific includes */
+#include <jtag/interface.h>
+#include <jtag/commands.h>
+#include <jtag/swd.h>
+#include <helper/time_support.h>
+#include <helper/replacements.h>
+#include <helper/list.h>
+#include <helper/binarybuffer.h>
+#include "libusb_helper.h"
+/* system includes */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#define JTAGIO_STA_OUT_TDI  (0x10)
+#define JTAGIO_STA_OUT_TMS  (0x02)
+#define JTAGIO_STA_OUT_TCK  (0x01)
+#define JTAGIO_STA_OUT_TRST (0x20)
+#define TDI_H               JTAGIO_STA_OUT_TDI
+#define TDI_L               0
+#define TMS_H               JTAGIO_STA_OUT_TMS
+#define TMS_L               0
+#define TCK_H               JTAGIO_STA_OUT_TCK
+#define TCK_L               0
+#define TRST_H              JTAGIO_STA_OUT_TRST
+#define TRST_L              0
+#define KHZ(n) ((n) * UINT64_C(1000))
+#define MHZ(n) ((n) * UINT64_C(1000000))
+#define GHZ(n) ((n) * UINT64_C(1000000000))
+#define CH347T_MPHSI_INTERFACE                 2 // the JTAG interface is 
number 2
+#define CH347F_MPHSI_INTERFACE                 4 // the JTAG interface is 
number 4
+#define DEFAULT_VENDOR_ID                              0x1a86 // if no vendor 
id is set use this CH347 default
+#define DEFAULT_PRODUCT_ID                             0x55dd // if no product 
id is set use this CH347 default
+#define HW_TDO_BUF_SIZE              4096
+#define SF_PACKET_BUF_SIZE           51200 /* Command packet length */
+#define UCMDPKT_DATA_MAX_BYTES_USBHS 507   /* The data length contained in each
+                                             command packet during USB
+                                             high-speed operation */
+#define USBC_PACKET_USBHS            512   /* Maximum data length per packet at
+                                             USB high speed */
+#define USBC_PACKET_USBHS_SINGLE     510   /* usb high speed max
+                                             package length */
+#define CH347_CMD_HEADER             3     /* Protocol header length */
+/* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */
+#define CH347_CMD_INFO_RD            0xCA /* Parameter acquisition, used to
+                                            obtain firmware version,
+                                            JTAG interface related parameters,
+                                            etc */
+#define CH347_CMD_JTAG_INIT          0xD0 /* JTAG Interface Initialization
+                                            Command */
+#define CH347_CMD_JTAG_BIT_OP        0xD1 /* JTAG interface pin bit control
+                                            command */
+#define CH347_CMD_JTAG_BIT_OP_RD     0xD2 /* JTAG interface pin bit control and
+                                            read commands */
+#define CH347_CMD_JTAG_DATA_SHIFT    0xD3 /* JTAG interface data shift
+                                            command */
+#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read
+                                            command */
+/* SWD */
+#define CH347_CMD_SWD_INIT  0xE5 /* SWD Interface Initialization Command */
+#define CH347_CMD_SWD       0xE8
+#define CH347_CMD_SWD_REG_W 0xA0 /* SWD Interface write reg */
+#define CH347_CMD_SWD_SEQ_W 0xA1 /* SWD Interface write spec seq */
+#define CH347_CMD_SWD_REG_R 0xA2 /* SWD Interface read  reg */
+#define CH347_MAX_SEND_CMD  0X20 /* max send cmd number */
+#define CH347_MAX_SEND_BUF  0X200
+#define CH347_MAX_RECV_BUF  0X200
+#define BUILD_UINT16(lo_byte, hi_byte)                                 \
+       ((unsigned short)(((lo_byte) & 0x00FF) + (((hi_byte) & 0x00FF) << 8)))
+#pragma pack(1)
+enum pack_size {
+       STANDARD_PACK = 0,
+       LARGER_PACK = 1,
+};
+struct ch347_info /* Record the CH347 pin status */
+{
+       int TMS;
+       int TDI;
+       int TCK;
+       int TRST;
+       int buffer_idx;
+       unsigned char buffer[SF_PACKET_BUF_SIZE];
+       int len_idx;
+       int len_value;
+       unsigned char last_cmd;
+       unsigned char read_buffer[SF_PACKET_BUF_SIZE];
+       unsigned int read_idx;
+       unsigned int read_count;
+       struct bit_copy_queue read_queue;
+       enum pack_size pack_size;
+};
+typedef struct _CH347_SWD_IO {
+       unsigned char usbcmd; /* 0xA0、0xA1、0xA2 */
+       unsigned char cmd;
+       unsigned int *dst;
+       unsigned int value;
+       struct list_head list_entry;
+} CH347_SWD_IO, *PCH347_SWD_IO;
+typedef struct _CH347_SWD_CONTEXT {
+       unsigned char send_buf[CH347_MAX_SEND_BUF];
+       unsigned char recv_buf[CH347_MAX_RECV_BUF];
+       unsigned int send_len;
+       unsigned int recv_len;
+       unsigned int need_recv_len;
+       int queued_retval;
+       unsigned char sent_cmd_count;
+       struct list_head send_cmd_head;
+       struct list_head free_cmd_head;
+       unsigned char *ch347_cmd_buf;
+} CH347_SWD_CONTEXT;
+#pragma pack()
+int dev_is_opened; /* Whether the device is turned on */
+unsigned long USBC_PACKET;
+static CH347_SWD_CONTEXT ch347_swd_context;
+static bool swd_mode;
+#include <jtag/drivers/libusb_helper.h>
+#define CH347_EPOUT 0x06u
+#define CH347_EPIN  0x86u
+struct libusb_device_handle *ch347_handle;
+static char *ch347_device_desc;
+static unsigned short ch347_vids[] = {DEFAULT_VENDOR_ID, 0};
+static unsigned short ch347_pids[] = {DEFAULT_PRODUCT_ID, 0};
+static unsigned int ch347_open_device(void)
+{
+       if (jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, 
&ch347_handle, NULL) != ERROR_OK)
+               return false;
+       else
+               return true;
+}
+static bool ch347_write_data(unsigned char *data, unsigned long *length)
+{
+       int ret, tmp = 0;
+       ret = jtag_libusb_bulk_write(ch347_handle,
+                                    CH347_EPOUT,
+                                    (char *)data,
+                                    *length,
+                                    1000, &tmp);
+       *length = tmp;
+       if (!ret)
+               return true;
+       else
+               return false;
+}
+static bool ch347_read_data(unsigned char *data, unsigned long *length)
+{
+       int ret, tmp = 0;
+       int size = *length;
+       ret = jtag_libusb_bulk_read(ch347_handle,
+                                   CH347_EPIN,
+                                   (char *)data,
+                                   size,
+                                   1000, &tmp);
+       *length = tmp;
+       if (!ret)
+               return true;
+       else
+               return false;
+}
+static bool ch347_close_device(void)
+{
+       jtag_libusb_close(ch347_handle);
+       return true;
+}
+struct ch347_info ch347;
+static int ch347_swd_run_queue(void);
+/* swd init func */
+static bool ch347swd_init(unsigned char clock_rate)
+{
+       unsigned char cmd_buf[128] = "";
+       unsigned long i = 0;
+       cmd_buf[i++] = CH347_CMD_SWD_INIT;
+       cmd_buf[i++] = 8; /* Data length is 6 */
+       cmd_buf[i++] = 0;
+       cmd_buf[i++] = 0x40;
+       cmd_buf[i++] = 0x42;
+       cmd_buf[i++] = 0x0f;       /* Reserved Bytes */
+       cmd_buf[i++] = 0x00;       /* Reserved Bytes */
+       cmd_buf[i++] = clock_rate; /* JTAG clock speed */
+       i += 3;                   /* Reserved Bytes */
+       unsigned long length = i;
+       if (!ch347_write_data(cmd_buf, &length) || length != i)
+               return false;
+       length = 4;
+       memset(cmd_buf, 0, sizeof(cmd_buf));
+       if (!ch347_read_data(cmd_buf, &length) || length != 4)
+               return false;
+       return true;
+}
+/**
+ *  hex_to_string - Hex Conversion String Function
+ *  @param buf    Point to a buffer to place the Hex data to be converted
+ *  @param size   Pointing to the length unit where data needs to be converted
+ *
+ *  @return Returns a converted string
+ */
+static char *hex_to_string(unsigned char *buf, unsigned int size)
+{
+       unsigned int i;
+       if (!buf)
+               return "NULL";
+       char *str = calloc(size * 2 + 1, 1);
+       for (i = 0; i < size; i++)
+               sprintf(str + 2 * i, "%02x ", buf[i]);
+       return str;
+}
+/**
+ *  ch347_write - CH347 Write
+ *  @param out_buffer    Point to a buffer to place the data to be written out
+ *  @param out_length   Pointing to the length unit, the input is the length 
to be
+ *                    written out, and the return is the actual written length
+ *
+ *  @return Write success returns 1, failure returns 0
+ */
+static int ch347_write(void *out_buffer, unsigned long *out_length)
+{
+       int ret = -1;
+       unsigned long length = *out_length, WI;
+       if (*out_length >= HW_TDO_BUF_SIZE)
+               length = HW_TDO_BUF_SIZE;
+       WI = 0;
+       while (1) {
+               ret = ch347_write_data((unsigned char *)out_buffer + WI,
+                                    &length);
+               if (!ret) {
+                       *out_length = 0;
+                       return false;
+               }
+               LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, length,
+                            hex_to_string((unsigned char *)out_buffer, length),
+                            (unsigned int)length);
+               WI += length;
+               if (*out_length <= WI)
+                       break;
+               if ((*out_length - WI) > HW_TDO_BUF_SIZE)
+                       length = HW_TDO_BUF_SIZE;
+               else
+                       length = *out_length - WI;
+       }
+       *out_length = WI;
+       return true;
+}
+/**
+ * ch347_read - CH347 Read
+ * @param out_buffer  Point to a buffer to place the data to be read in
+ * @param out_length Pointing to the length unit, the input is the length to
+ *                 be read, and the return is the actual read length
+ *
+ * @return Write success returns 1, failure returns 0
+ */
+static int ch347_read(void *out_buffer, unsigned long *out_length)
+{
+       unsigned long rlength = *out_length, WI;
+       /* The maximum allowable reading for a single read is 4096B of data.
+          If it exceeds the allowable reading limit, it will be calculated as
+          4096B */
+       if (rlength > HW_TDO_BUF_SIZE)
+               rlength = HW_TDO_BUF_SIZE;
+       WI = 0;
+       while (1) {
+               if (!ch347_read_data((unsigned char *)out_buffer + WI,
+                                  &rlength)) {
+                       LOG_ERROR("read data failure.");
+                       return false;
+               }
+               WI += rlength;
+               if (*out_length <= WI)
+                       break;
+               if ((*out_length - WI) > HW_TDO_BUF_SIZE)
+                       rlength = HW_TDO_BUF_SIZE;
+               else
+                       rlength = *out_length - WI;
+       }
+       LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, WI,
+                    hex_to_string((unsigned char *)out_buffer, WI), (unsigned 
int)WI);
+       *out_length = WI;
+       return true;
+}
+static void ch347_read_scan(unsigned char *buffer_ptr, unsigned int length)
+{
+       unsigned long read_size = 0;
+       unsigned long rx_len = 0;
+       unsigned long index = 0;
+       unsigned long read_buf_index = 0;
+       unsigned char *read_buf = NULL;
+       int data_len = 0, i = 0; /*, this_bits = 0; */
+       read_size = length;
+       rx_len = read_size;
+       index = 0;
+       read_buf_index = 0;
+       read_buf = calloc(sizeof(unsigned char), read_size);
+       if (!ch347_read(read_buf, &rx_len)) {
+               LOG_ERROR("ch347_read read data failure.");
+               return;
+       }
+       while (index < read_size) { /* deal with the CH347_CMD_JTAG_BIT_OP_RD  
or  CH347_CMD_JTAG_DATA_SHIFT_RD */
+               if (read_buf[index] == CH347_CMD_JTAG_DATA_SHIFT_RD) {
+                       data_len = read_buf[++index] & 0xFF;
+                       data_len += (read_buf[++index] & 0xFF) << 8;
+                       memcpy(buffer_ptr + read_buf_index, &read_buf[index + 
1],
+                              data_len);
+                       read_buf_index += data_len;
+                       index += data_len + 1;
+               } else if (read_buf[index] == CH347_CMD_JTAG_BIT_OP_RD) {
+                       data_len = read_buf[++index] & 0xFF;
+                       data_len += (read_buf[++index] & 0xFF) << 8;
+                       for (i = 0; i < data_len; i++) {
+                               if (read_buf[index + 1 + i] == 0x01)
+                                       *(buffer_ptr + read_buf_index) |= (1 << 
i);
+                               else
+                                       *(buffer_ptr + read_buf_index) &= ~(1 
<< i);
+                       }
+                       read_buf_index += 1;
+                       index += data_len + 1;
+               } else {
+                       // LOG_ERROR("readbuf read_commend error");
+                       *(buffer_ptr + read_buf_index) = read_buf[index];
+                       read_buf_index++;
+                       index++;
+               }
+       }
+       if (read_buf) {
+               free(read_buf);
+               read_buf = NULL;
+       }
+}
+static void ch347_flush_buffer(void)
+{
+       unsigned long retlen = ch347.buffer_idx;
+       int nb = ch347.buffer_idx, ret = ERROR_OK;
+       while (ret == ERROR_OK && nb > 0) {
+               ret = ch347_write(ch347.buffer, &retlen);
+               nb -= retlen;
+       }
+       memset(&ch347.buffer, 0, sizeof(ch347.buffer));
+       ch347.buffer_idx = 0;
+       ch347.last_cmd = 0;
+       ch347.len_idx = 0;
+       ch347.len_value = 0;
+       if (ch347.read_count == 0)
+               return;
+       if (ch347.pack_size == LARGER_PACK) {
+               ch347_read_scan(&ch347.read_buffer[0], ch347.read_count);
+               bit_copy_execute(&ch347.read_queue);
+               memset(ch347.read_buffer, 0, SF_PACKET_BUF_SIZE);
+               ch347.read_count = 0;
+               ch347.read_idx = 0;
+       }
+}
+static void ch347_in_buffer(unsigned char byte)
+{
+       if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1)
+               ch347_flush_buffer();
+       ch347.buffer[ch347.buffer_idx] = byte;
+       ch347.buffer_idx++;
+       if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) == 0)
+               ch347_flush_buffer();
+}
+static void ch347_in_buffer_bytes(unsigned char *bytes, unsigned long 
bytes_length)
+{
+       if ((ch347.buffer_idx + bytes_length) > SF_PACKET_BUF_SIZE)
+               ch347_flush_buffer();
+       memcpy(&ch347.buffer[ch347.buffer_idx], bytes, bytes_length);
+       ch347.buffer_idx += bytes_length;
+       if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1)
+               ch347_flush_buffer();
+}
+static void combine_packets(unsigned char cmd, int cur_idx, unsigned long len)
+{
+       if (cmd != ch347.last_cmd) {
+               ch347.buffer[cur_idx] = cmd;
+               ch347.buffer[cur_idx + 1] =
+                       (unsigned char)(((len - CH347_CMD_HEADER) >> 0) & 0xFF);
+               ch347.buffer[cur_idx + 2] =
+                       (unsigned char)(((len - CH347_CMD_HEADER) >> 8) & 0xFF);
+               /* update the ch347 struct */
+               ch347.last_cmd = cmd;
+               ch347.len_idx = cur_idx + 1;
+               ch347.len_value = (len - CH347_CMD_HEADER);
+       } else {
+               /* update the ch347 struct cmd data leng */
+               ch347.len_value += (len - CH347_CMD_HEADER);
+               /* update the cmd packet valid leng */
+               ch347.buffer[ch347.len_idx] = (unsigned char)((ch347.len_value 
>> 0) & 0xFF);
+               ch347.buffer[ch347.len_idx + 1] = (unsigned 
char)((ch347.len_value >> 8) & 0xFF);
+               /* update the buffer data leng */
+               memcpy(&ch347.buffer[cur_idx],
+                      &ch347.buffer[cur_idx + CH347_CMD_HEADER],
+                      (len - CH347_CMD_HEADER));
+               /* update the ch347 buffer index */
+               ch347.buffer_idx -= CH347_CMD_HEADER;
+       }
+}
+/**
+ * ch347_clock_tims - Function used to change the TMS value at the
+ * rising edge of TCK to switch its Tap state
+ * @param bit_bangPkt Protocol package
+ * @param tms TMS value to be changed
+ * @param BI Protocol packet length
+ *
+ * @return Return protocol packet length
+ */
+static unsigned long ch347_clock_tims(int tms, unsigned long BI)
+{
+       unsigned char data = 0;
+       unsigned char cmd = 0;
+       if (tms == 1)
+               cmd = TMS_H;
+       else
+               cmd = TMS_L;
+       BI += 2;
+       data = cmd | TDI_L | TCK_L | TRST_H;
+       ch347_in_buffer(data);
+       data = cmd | TDI_L | TCK_H | TRST_H;
+       ch347_in_buffer(data);
+       ch347.TMS = cmd;
+       ch347.TDI = TDI_L;
+       ch347.TCK = TCK_H;
+       ch347.TRST = TRST_H;
+       return BI;
+}
+/**
+ * ch347_idle_clock - Function to ensure that the clock is in a low state
+ * @param bit_bangPkt Protocol package
+ * @param BI Protocol packet length
+ *
+ * @return Return protocol packet length
+ */
+static unsigned long ch347_idle_clock(unsigned long BI)
+{
+       unsigned char byte = 0;
+       byte |= ch347.TMS ? TMS_H : TMS_L;
+       byte |= ch347.TDI ? TDI_H : TDI_L;
+       byte |= ch347.TRST ? TRST_H : TRST_L;
+       BI++;
+       ch347_in_buffer(byte);
+       return BI;
+}
+/**
+ * ch347_tms_change - Function that performs state switching by changing the 
value of TMS
+ * @param tms_value The TMS values that need to be switched form one byte of 
data in the switching order
+ * @param step The number of bit values that need to be read from the 
tms_value value
+ * @param skip Count from the skip bit of tms_value to step
+ *
+ */
+static void ch347_tms_change(const unsigned char *tms_value, int step, int 
skip)
+{
+       int i;
+       int index = ch347.buffer_idx;
+       unsigned long BI, retlen, cmdlen;
+       BI = CH347_CMD_HEADER;
+       retlen = CH347_CMD_HEADER;
+       LOG_DEBUG_IO("(TMS Value: %02x..., step = %d, skip = %d)", tms_value[0],
+                    step, skip);
+       for (i = 0; i < 3; i++)
+               ch347_in_buffer(0);
+       for (i = skip; i < step; i++) {
+               retlen = ch347_clock_tims((tms_value[i / 8] >> (i % 8)) & 0x01, 
BI);
+               BI = retlen;
+       }
+       cmdlen = ch347_idle_clock(BI);
+       combine_packets(CH347_CMD_JTAG_BIT_OP, index, cmdlen);
+}
+/**
+ * ch347_tms - By ch347_ execute_ Queue call
+ * @param cmd Upper layer transfer command parameters
+ *
+ */
+static void ch347_tms(struct tms_command *cmd)
+{
+       LOG_DEBUG_IO("(step: %d)", cmd->num_bits);
+       ch347_tms_change(cmd->bits, cmd->num_bits, 0);
+}
+/**
+ * CH347_Reset - CH347 Reset Tap Status Function
+ * @brief If there are more than six consecutive TCKs and TMS is high, the 
state
+ *         machine can be set to a Test-Logic-Reset state
+ *
+ */
+static int ch347_reset(int trst, int srst)
+{
+       LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst);
+       unsigned char bit_bang[512] = "", BII, i;
+       unsigned long tx_len;
+       if (!swd_mode) {
+               BII = CH347_CMD_HEADER;
+               for (i = 0; i < 7; i++) {
+                       bit_bang[BII++] = TMS_H | TDI_L | TCK_L;
+                       bit_bang[BII++] = TMS_H | TDI_L | TCK_H;
+               }
+               bit_bang[BII++] = TMS_H | TDI_L | TCK_L;
+               ch347.TCK = TCK_L;
+               ch347.TDI = TDI_L;
+               ch347.TMS = 0;
+               bit_bang[0] = CH347_CMD_JTAG_BIT_OP;
+               bit_bang[1] = BII - CH347_CMD_HEADER;
+               bit_bang[2] = 0;
+               tx_len = BII;
+               if (!ch347_write(bit_bang, &tx_len) && tx_len != BII) {
+                       LOG_ERROR("JTAG_Init send usb data failure.");
+                       return false;
+               }
+       }
+       return ERROR_OK;
+}
+/**
+ * ch347_movepath - Obtain the current Tap status and switch to the status TMS
+ *                  value passed down by cmd
+ * @param cmd Upper layer transfer command parameters
+ *
+ */
+static void ch347_movepath(struct pathmove_command *cmd)
+{
+       int i;
+       int index = ch347.buffer_idx;
+       unsigned long BI, retlen = 0, cmdlen;
+       BI = CH347_CMD_HEADER;
+       for (i = 0; i < 3; i++)
+               ch347_in_buffer(0);
+       LOG_DEBUG_IO("(num_states=%d, last_state=%d)",
+                    cmd->num_states, cmd->path[cmd->num_states - 1]);
+       for (i = 0; i < cmd->num_states; i++) {
+               if (tap_state_transition(tap_get_state(), false) ==
+                   cmd->path[i])
+                       retlen = ch347_clock_tims(0, BI);
+               BI = retlen;
+               if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
+                       retlen = ch347_clock_tims(1, BI);
+               BI = retlen;
+               tap_set_state(cmd->path[i]);
+       }
+       cmdlen = ch347_idle_clock(BI);
+       combine_packets(CH347_CMD_JTAG_BIT_OP, index, cmdlen);
+}
+/**
+ * ch347_movestate - Toggle the Tap state to the Target state stat
+ * @param stat Pre switch target path
+ * @param skip Number of digits to skip
+ *
+ */
+static void ch347_movestate(tap_state_t state, int skip)
+{
+       unsigned char tms_scan;
+       int tms_len;
+       LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()),
+                    tap_state_name(state));
+       if (tap_get_state() == state)
+               return;
+       tms_scan = tap_get_tms_path(tap_get_state(), state);
+       tms_len = tap_get_tms_path_len(tap_get_state(), state);
+       ch347_tms_change(&tms_scan, tms_len, skip);
+       tap_set_state(state);
+}
+/**
+ * ch347_writeread - CH347 Batch read/write function
+ * @param bits     Read and write data this time
+ * @param nb_bits  Incoming data length
+ * @param scan     The transmission method of incoming data to determine 
whether
+ *                 to perform data reading
+ */
+static void ch347_writeread(struct scan_command *cmd, unsigned char *bits,
+                           int nb_bits, enum scan_type scan)
+{
+       int nb8 = nb_bits / 8;
+       int nb1 = nb_bits % 8;
+       int i, num_bits = 0;
+       bool is_read = false; /*, isLastByte = false */
+       unsigned char tms_bit = 0, tdi_bit = 0, cmd_bit;
+       static unsigned char byte0[SF_PACKET_BUF_SIZE];
+       unsigned char *read_data = calloc(SF_PACKET_BUF_SIZE, 1);
+       unsigned long read_len = 0;
+       unsigned long BI = 0, DI, DII, pkt_data_len, data_len = 0, temp_index,
+               total_read_length = 0, temp_length = 0;
+       if (ch347.pack_size == LARGER_PACK) {
+               if ((ch347.read_count >= (510 * 1)))
+                       ch347_flush_buffer();
+       } else {
+               ch347_flush_buffer();
+       }
+       if (nb8 > 0 && nb1 == 0) {
+               nb8--;
+               nb1 = 8;
+       }
+       is_read = (scan == SCAN_IN || scan == SCAN_IO);
+       DI = 0;
+       BI = 0;
+       while (DI < (unsigned long)nb8) {
+               if ((nb8 - DI) > UCMDPKT_DATA_MAX_BYTES_USBHS)
+                       pkt_data_len = UCMDPKT_DATA_MAX_BYTES_USBHS;
+               else
+                       pkt_data_len = nb8 - DI;
+               DII = pkt_data_len;
+               if (is_read)
+                       ch347_in_buffer(CH347_CMD_JTAG_DATA_SHIFT_RD);
+               else
+                       ch347_in_buffer(CH347_CMD_JTAG_DATA_SHIFT);
+               /* packet data don't deal D3 & D4 */
+               if (ch347.last_cmd != CH347_CMD_JTAG_DATA_SHIFT_RD ||
+                   ch347.last_cmd != CH347_CMD_JTAG_DATA_SHIFT) {
+                       /* update the ch347 struct */
+                       ch347.last_cmd = 0;
+                       ch347.len_idx = 0;
+                       ch347.len_value = 0;
+               }
+               ch347_in_buffer((unsigned char)(pkt_data_len >> 0) & 0xFF);
+               ch347_in_buffer((unsigned char)(pkt_data_len >> 8) & 0xFF);
+               if (bits)
+                       ch347_in_buffer_bytes(&bits[DI], pkt_data_len);
+               else
+                       ch347_in_buffer_bytes(byte0, pkt_data_len);
+               DI += DII;
+               temp_length += (DII + CH347_CMD_HEADER);
+       }
+       total_read_length += temp_length;
+       if (is_read) {
+               ch347.read_count += temp_length;
+               read_len += temp_length;
+       }
+       if (bits) {
+               cmd_bit = is_read ? CH347_CMD_JTAG_BIT_OP_RD : 
CH347_CMD_JTAG_BIT_OP;
+               data_len = (nb1 * 2) + 1;
+               if (cmd_bit != ch347.last_cmd) {
+                       ch347_in_buffer(cmd_bit);
+                       ch347_in_buffer((unsigned char)(data_len >> 0) & 0xFF);
+                       ch347_in_buffer((unsigned char)(data_len >> 8) & 0xFF);
+                       ch347.last_cmd = cmd_bit;
+                       ch347.len_idx = ch347.buffer_idx - 2;
+                       ch347.len_value = data_len;
+               } else {
+                       /* update the ch347 struct cmd data leng */
+                       ch347.len_value += data_len;
+                       /* update the cmd packet valid leng */
+                       ch347.buffer[ch347.len_idx] =
+                               (unsigned char)(ch347.len_value >> 0) & 0xFF;
+                       ch347.buffer[ch347.len_idx + 1] =
+                               (unsigned char)(ch347.len_value >> 8) & 0xFF;
+               }
+               tms_bit = TMS_L;
+               for (i = 0; i < nb1; i++) {
+                       if ((bits[nb8] >> i) & 0x01)
+                               tdi_bit = TDI_H;
+                       else
+                               tdi_bit = TDI_L;
+                       if ((i + 1) == nb1)
+                               tms_bit = TMS_H;
+                       ch347_in_buffer(tms_bit | tdi_bit | TCK_L | TRST_H);
+                       ch347_in_buffer(tms_bit | tdi_bit | TCK_H | TRST_H);
+               }
+               ch347_in_buffer(tms_bit | tdi_bit | TCK_L | TRST_H);
+       }
+       ch347.TMS = tms_bit;
+       ch347.TDI = tdi_bit;
+       ch347.TCK = TCK_L;
+       if (is_read) {
+               temp_length = ((data_len / 2) + CH347_CMD_HEADER);
+               total_read_length += temp_length;
+               ch347.read_count += temp_length;
+               read_len += temp_length;
+               DI = 0;
+               BI = 0;
+       }
+       int offset = 0, bit_count = 0;
+       if (is_read && total_read_length > 0) {
+               if (ch347.pack_size == STANDARD_PACK && bits && cmd) {
+                       ch347_flush_buffer();
+                       ch347_read_scan(read_data, read_len);
+               }
+               for (i = 0; i < cmd->num_fields; i++) {
+                       /* if neither in_value nor in_handler
+                        * are specified we don't have to examine this field
+                        */
+                       LOG_DEBUG("fields[%i].in_value[%i], offset: %d",
+                                 i, cmd->fields[i].num_bits, offset);
+                       num_bits = cmd->fields[i].num_bits;
+                       if (ch347.pack_size == LARGER_PACK)
+                               bit_count += num_bits;
+                       if (cmd->fields[i].in_value) {
+                               if (ch347.pack_size == LARGER_PACK) {
+                                       bit_copy_queued(&ch347.read_queue,
+                                               cmd->fields[i].in_value,
+                                               0,
+                                               
&ch347.read_buffer[ch347.read_idx],
+                                               offset, num_bits);
+                                       if (num_bits > 7)
+                                               ch347.read_idx += 
DIV_ROUND_UP(bit_count, 8);
+                               } else {
+                                       num_bits = cmd->fields[i].num_bits;
+                                       unsigned char *captured = 
buf_set_buf(read_data, bit_count,
+                                               malloc(DIV_ROUND_UP(num_bits,
+                                                                   8)), 0,
+                                               num_bits);
+                                       if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) {
+                                               char *char_buf =
+                                                       buf_to_hex_str(captured,
+                                                               (num_bits >
+                                                                DEBUG_JTAG_IOZ)
+                                                               ? DEBUG_JTAG_IOZ
+                                                               : num_bits);
+                                               free(char_buf);
+                                       }
+                                       buf_cpy(captured,
+                                               cmd->fields[i].in_value,
+                                               num_bits);
+                                       free(captured);
+                               }
+                       } else {
+                               LOG_DEBUG_IO("cmd->fields with no data");
+                       }
+                       if (ch347.pack_size == LARGER_PACK)
+                               offset += num_bits;
+                       else
+                               bit_count += cmd->fields[i].num_bits;
+               }
+       }
+       temp_index = ch347.buffer_idx;
+       for (i = 0; i < CH347_CMD_HEADER; i++)
+               ch347_in_buffer(0);
+       BI = CH347_CMD_HEADER;
+       BI = ch347_idle_clock(BI);
+       combine_packets(CH347_CMD_JTAG_BIT_OP, temp_index, BI);
+       if (read_data) {
+               free(read_data);
+               read_data = NULL;
+       }
+}
+static void ch347_runtest(int cycles, tap_state_t state)
+{
+       LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state);
+       if (tap_get_state() != TAP_IDLE)
+               ch347_movestate(TAP_IDLE, 0);
+       unsigned char tms_value = 0;
+       ch347_tms_change(&tms_value, 7, 1);
+       ch347_writeread(NULL, NULL, cycles, SCAN_OUT);
+       ch347_movestate(state, 0);
+}
+static void ch347_tableclocks(int cycles)
+{
+       LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles);
+       ch347_writeread(NULL, NULL, cycles, SCAN_OUT);
+}
+/**
+ * ch347_scan - Switch to SHIFT-DR or SHIFT-IR status for scanning
+ * @param cmd Upper layer transfer command parameters
+ *
+ * @return Success returns ERROR_OK
+ */
+static int ch347_scan(struct scan_command *cmd)
+{
+       int scan_bits;
+       unsigned char *buf = NULL;
+       enum scan_type type;
+       int ret = ERROR_OK;
+       static const char *const type2str[] = {
+               "", "SCAN_IN", "SCAN_OUT", "SCAN_IO"
+       };
+       char *log_buf = NULL;
+       type = jtag_scan_type(cmd);
+       scan_bits = jtag_build_buffer(cmd, &buf);
+       if (cmd->ir_scan)
+               ch347_movestate(TAP_IRSHIFT, 0);
+       else
+               ch347_movestate(TAP_DRSHIFT, 0);
+       log_buf = hex_to_string(buf, DIV_ROUND_UP(scan_bits, 8));
+       LOG_DEBUG_IO("Scan");
+       LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)",
+                    __func__,
+                    cmd->ir_scan ? "IRSCAN" : "DRSCAN",
+                    type2str[type],
+                    scan_bits, log_buf, cmd->end_state);
+       free(log_buf);
+       ch347_writeread(cmd, buf, scan_bits, type);
+       free(buf);
+       ch347_movestate(cmd->end_state, 1);
+       return ret;
+}
+static void ch347_sleep(int us)
+{
+       LOG_DEBUG_IO("%s(us=%d)", __func__, us);
+       jtag_sleep(us);
+}
+static int ch347_execute_queue(struct jtag_command *cmd)
+{
+       int ret = ERROR_OK;
+       for (cmd = jtag_command_queue_get(); ret == ERROR_OK && cmd;
+                cmd = cmd->next) {
+               switch (cmd->type) {
+               case JTAG_RESET:
+                       LOG_DEBUG_IO("JTAG_RESET : %d %d.\n",
+                                    cmd->cmd.reset->trst,
+                                    cmd->cmd.reset->srst);
+                       ch347_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+                       break;
+               case JTAG_RUNTEST:
+                       ch347_runtest(cmd->cmd.runtest->num_cycles,
+                                     cmd->cmd.runtest->end_state);
+                       break;
+               case JTAG_STABLECLOCKS:
+                       ch347_tableclocks(cmd->cmd.stableclocks->num_cycles);
+                       break;
+               case JTAG_TLR_RESET:
+                       ch347_movestate(cmd->cmd.statemove->end_state, 0);
+                       break;
+               case JTAG_PATHMOVE:
+                       ch347_movepath(cmd->cmd.pathmove);
+                       break;
+               case JTAG_TMS:
+                       ch347_tms(cmd->cmd.tms);
+                       break;
+               case JTAG_SLEEP:
+                       ch347_sleep(cmd->cmd.sleep->us);
+                       break;
+               case JTAG_SCAN:
+                       ret = ch347_scan(cmd->cmd.scan);
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown JTAG command type 0x%X",
+                                 cmd->type);
+                       ret = ERROR_FAIL;
+                       break;
+               }
+       }
+       ch347_flush_buffer();
+       return ret;
+}
+/**
+ * ch347_init - CH347 Initialization function
+ *
+ *  Todo:
+ *                Initialize dynamic library functions
+ *                Open Device
+ *  @return Success returns 0, failure returns ERROR_FAIL
+ */
+static int ch347_init(void)
+{
+       int retval;
+       dev_is_opened = ch347_open_device();
+       if (dev_is_opened) {
+               LOG_INFO("CH347 Open Succ.");
+       } else {
+               LOG_ERROR("CH347 Open Error.");
+               return ERROR_FAIL;
+       }
+       if (ch347_pids[0] == DEFAULT_PRODUCT_ID)
+               retval = libusb_claim_interface(ch347_handle, 
CH347T_MPHSI_INTERFACE);
+       else
+               retval = libusb_claim_interface(ch347_handle, 
CH347F_MPHSI_INTERFACE);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("CH347 unable to claim interface: %s", 
libusb_error_name(retval));
+               jtag_libusb_close(ch347_handle);
+               return retval;
+       }
+       if (!swd_mode) {
+               USBC_PACKET = USBC_PACKET_USBHS;
+               /* ch347 init */
+               ch347.TCK = TCK_L;
+               ch347.TMS = TMS_H;
+               ch347.TDI = TDI_L;
+               ch347.TRST = TRST_H;
+               ch347.buffer_idx = 0;
+               memset(&ch347.buffer, 0, SF_PACKET_BUF_SIZE);
+               ch347.len_idx = 0;
+               ch347.len_value = 0;
+               ch347.last_cmd = 0;
+               memset(&ch347.read_buffer, 0, SF_PACKET_BUF_SIZE);
+               ch347.read_count = 0;
+               ch347.read_idx = 0;
+               bit_copy_queue_init(&ch347.read_queue);
+               tap_set_state(TAP_RESET);
+       } else { /* swd init */
+               ch347swd_init(1);
+       }
+       return 0;
+}
+/**
+ * ch347_quit - CH347 Device Release Function
+ *
+ * Todo:
+ *              Reset JTAG pin signal
+ *              Close
+ *  @return always returns 0
+ */
+static int ch347_quit(void)
+{
+       unsigned long retlen = 4;
+       unsigned char byte[4] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, ch347.TRST};
+       if (!swd_mode) {
+               ch347_write(byte, &retlen);
+               bit_copy_discard(&ch347.read_queue);
+       }
+       if (dev_is_opened) {
+               ch347_close_device();
+               LOG_INFO("Close the CH347.");
+               dev_is_opened = false;
+       }
+       return 0;
+}
+static bool check_speed(unsigned char clock_rate)
+{
+       unsigned long i = 0, j;
+       bool ret;
+       unsigned char cmd_buf[32] = "";
+       cmd_buf[i++] = CH347_CMD_JTAG_INIT;
+       cmd_buf[i++] = 6;
+       cmd_buf[i++] = 0;
+       cmd_buf[i++] = 0;
+       cmd_buf[i++] = clock_rate;
+       for (j = 0; j < 4; j++)
+               cmd_buf[i++] = ch347.TCK | ch347.TDI | ch347.TMS | ch347.TRST;
+       unsigned long length = i;
+       if (!ch347_write_data(cmd_buf, &length) || length != i)
+               return false;
+       length = 4;
+       memset(cmd_buf, 0, sizeof(cmd_buf));
+       if (!ch347_read_data(cmd_buf, &length) || length != 4) {
+               LOG_ERROR("LINE == %d FALSE", __LINE__);
+               return false;
+       }
+       ret = ((cmd_buf[0] == CH347_CMD_JTAG_INIT) && 
(cmd_buf[CH347_CMD_HEADER] == 0));
+       return ret;
+}
+static bool ch347_jtag_init(unsigned char clock_rate)
+{
+       ch347.pack_size = (check_speed(0x09) == true) ? STANDARD_PACK : 
LARGER_PACK;
+       if (ch347.pack_size == STANDARD_PACK) {
+               if (clock_rate - 2 < 0)
+                       return check_speed(0);
+               else
+                       return check_speed(clock_rate - 2);
+       }
+       return check_speed(clock_rate);
+}
+/**
+ * ch347_speed - CH347 TCK frequency setting
+ *  @param speed Frequency size set
+ *  @return Success returns ERROR_OK,failed returns FALSE
+ */
+static int ch347_speed(int speed)
+{
+       unsigned long i = 0;
+       unsigned char clock_rate;
+       int ret = -1;
+       int speed_clock[8] = {
+               KHZ(468.75), KHZ(937.5), MHZ(1.875),
+               MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60)
+       };
+       if (!swd_mode) {
+               for (i = 0; i < ARRAY_SIZE(speed_clock); i++) {
+                       if (speed >= speed_clock[i] &&
+                           speed <= speed_clock[i + 1]) {
+                               clock_rate = i + 1;
+                               ret = ch347_jtag_init(clock_rate);
+                               if (!ret)
+                                       LOG_ERROR("Couldn't set CH347 TCK 
speed");
+                               return ERROR_OK;
+                       } else if (speed < speed_clock[0]) {
+                               ret = ch347_jtag_init(0);
+                               if (!ret) {
+                                       LOG_ERROR("Couldn't set CH347 TCK 
speed");
+                                       return ret;
+                               } else {
+                                       return ERROR_OK;
+                               }
+                       }
+               }
+       }
+       return ERROR_OK;
+}
+static int ch347_speed_div(int speed, int *khz)
+{
+       *khz = speed / 1000;
+       return ERROR_OK;
+}
+static int ch347_khz(int khz, int *jtag_speed)
+{
+       if (khz == 0) {
+               LOG_ERROR("Couldn't support the adapter speed");
+               return ERROR_FAIL;
+       }
+       *jtag_speed = khz * 1000;
+       return ERROR_OK;
+}
+static int ch347_trst_out(unsigned char status)
+{
+       unsigned long BI = 0;
+       unsigned char byte = 0;
+       unsigned char cmd_packet[4] = "";
+       cmd_packet[BI++] = CH347_CMD_JTAG_BIT_OP;
+       cmd_packet[BI++] = 0x01;
+       cmd_packet[BI++] = 0;
+       byte = ch347.TCK | ch347.TDI | ch347.TMS | (ch347.TRST =
+                                                   (status ? TRST_H : TRST_L));
+       cmd_packet[BI++] = byte;
+       if (!ch347_write(cmd_packet, &BI)) {
+               LOG_ERROR("TRST set failure.");
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+COMMAND_HANDLER(ch347_handle_vid_pid_command)
+{
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ch347_vids[0]);
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ch347_pids[0]);
+       return ERROR_OK;
+}
+COMMAND_HANDLER(ch347_trst)
+{
+       ch347_trst_out(TRST_L);
+       jtag_sleep(atoi(CMD_ARGV[0]) * 1000);
+       ch347_trst_out(TRST_H);
+       return ERROR_OK;
+}
+static const struct command_registration ch347_subcommand_handlers[] = {
+       {
+               .name = "vid_pid",
+               .handler = &ch347_handle_vid_pid_command,
+               .mode = COMMAND_CONFIG,
+               .help = "",
+               .usage = "",
+       },
+       {
+               .name = "jtag_ntrst_delay",
+               .handler = &ch347_trst,
+               .mode = COMMAND_ANY,
+               .help = "set the trst of the CH347 device that is used as JTAG",
+               .usage = "[milliseconds]",
+       },
+       COMMAND_REGISTRATION_DONE};
+static const struct command_registration ch347_command_handlers[] = {
+       {
+               .name = "ch347",
+               .mode = COMMAND_ANY,
+               .help = "perform ch347 management",
+               .chain = ch347_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE};
+static int ch347_swd_init(void)
+{
+       PCH347_SWD_IO pswd_io;
+       LOG_INFO("CH347 SWD mode enabled");
+       swd_mode = true;
+       memset(&ch347_swd_context, 0, sizeof(ch347_swd_context));
+       INIT_LIST_HEAD(&ch347_swd_context.send_cmd_head);
+       INIT_LIST_HEAD(&ch347_swd_context.free_cmd_head);
+       ch347_swd_context.queued_retval = ERROR_OK;
+       /* 0XE8 + 2byte len + N byte cmds */
+       ch347_swd_context.send_len = CH347_CMD_HEADER;
+       /*  0XE8 + 2byte len + N byte ack + data */
+       ch347_swd_context.need_recv_len = CH347_CMD_HEADER;
+       ch347_swd_context.ch347_cmd_buf = malloc(128 * sizeof(CH347_SWD_IO));
+       if (ch347_swd_context.ch347_cmd_buf) {
+               pswd_io = (PCH347_SWD_IO)ch347_swd_context.ch347_cmd_buf;
+               for (int i = 0; i < 128; i++, pswd_io++) {
+                       INIT_LIST_HEAD(&pswd_io->list_entry);
+                       list_add_tail(&pswd_io->list_entry,
+                                     &ch347_swd_context.free_cmd_head);
+               }
+       }
+       return ch347_swd_context.ch347_cmd_buf ? ERROR_OK : ERROR_FAIL;
+}
+static PCH347_SWD_IO ch347_get_one_swd_io(void)
+{
+       PCH347_SWD_IO pswd_io;
+       if (list_empty(&ch347_swd_context.free_cmd_head))
+               return NULL;
+       pswd_io = list_first_entry(&ch347_swd_context.free_cmd_head, 
CH347_SWD_IO, list_entry);
+               list_del_init(&pswd_io->list_entry);
+               pswd_io->cmd = 0;
+               pswd_io->usbcmd = CH347_CMD_SWD_SEQ_W;
+               pswd_io->dst = NULL;
+               return pswd_io;
+}
+static void ch347_swd_queue_flush(void)
+{
+       unsigned long length = ch347_swd_context.send_len;
+       ch347_swd_context.send_buf[0] = (unsigned char)CH347_CMD_SWD;
+       ch347_swd_context.send_buf[1] = (unsigned 
char)(ch347_swd_context.send_len -
+                                                 CH347_CMD_HEADER);
+       ch347_swd_context.send_buf[2] = (unsigned 
char)((ch347_swd_context.send_len -
+                                                  CH347_CMD_HEADER) >> 8);
+       if (!ch347_write_data(ch347_swd_context.send_buf, &length) ||
+           length != ch347_swd_context.send_len) {
+               ch347_swd_context.queued_retval = ERROR_FAIL;
+               LOG_DEBUG("ch347_write_data error ");
+               return;
+       }
+       ch347_swd_context.recv_len = 0;
+       do {
+               length = CH347_MAX_RECV_BUF - ch347_swd_context.recv_len;
+               if 
(!ch347_read_data(&ch347_swd_context.recv_buf[ch347_swd_context.recv_len],
+                                  &length)) {
+                       ch347_swd_context.queued_retval = ERROR_FAIL;
+                       LOG_DEBUG("ch347_read_data error ");
+                       return;
+               }
+               ch347_swd_context.recv_len += length;
+       } while (ch347_swd_context.recv_len < ch347_swd_context.need_recv_len);
+       if (ch347_swd_context.need_recv_len > ch347_swd_context.recv_len) {
+               LOG_ERROR("%d : write/read failed %d %d",
+                         __LINE__,
+                         ch347_swd_context.recv_len,
+                         ch347_swd_context.need_recv_len);
+       }
+}
+static void ch347_wrtie_swd_reg(unsigned char cmd, const unsigned char *out, 
unsigned char parity)
+{
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] =
+               CH347_CMD_SWD_REG_W;
+       /* 8bit + 32bit +1bit */
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x29;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[0];
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[1];
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[2];
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[3];
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = parity;
+       /* 0xA0 +  1 byte(3bit ACK) */
+       ch347_swd_context.need_recv_len += (1 + 1);
+}
+static void ch347_wrtie_spec_seq(const unsigned char *out, unsigned char 
out_len)
+{
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] =
+               CH347_CMD_SWD_SEQ_W;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out_len;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00;
+       for (unsigned char i = 0; i < DIV_ROUND_UP(out_len, 8); i++) {
+               if (out)
+                       
ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[i];
+               else
+                       
ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00;
+       }
+       ch347_swd_context.need_recv_len += 1; /* 0xA1 */
+}
+static void ch347_read_swd_reg(unsigned char cmd)
+{
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] =
+               CH347_CMD_SWD_REG_R;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x22;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00;
+       ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd;
+       /* 0xA2 + 1 byte(3bit ACK) + 4 byte(data) +
+          1 byte(1bit parity+1bit trn) */
+       ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1;
+}
+static int ch347_swd_switch_out(enum swd_special_seq seq, const unsigned char 
*out,
+                               unsigned int out_len)
+{
+       PCH347_SWD_IO pswd_io;
+       if ((ch347_swd_context.send_len +
+            (1 + 2 + DIV_ROUND_UP(out_len, 8))) > CH347_MAX_SEND_BUF) {
+               return ERROR_FAIL;
+       }
+       if ((ch347_swd_context.need_recv_len + 2) > CH347_MAX_RECV_BUF)
+               return ERROR_FAIL;
+       pswd_io = ch347_get_one_swd_io();
+       if (pswd_io) {
+               ch347_wrtie_spec_seq(out, out_len);
+               list_add_tail(&pswd_io->list_entry,
+                             &ch347_swd_context.send_cmd_head);
+               return ERROR_OK;
+       } else {
+               return ERROR_FAIL;
+       }
+}
+/* check read/write REG can fill in remaining buff */
+static bool ch347_chk_buf_size(unsigned char cmd, unsigned int ap_delay_clk)
+{
+       bool bflush;
+       unsigned int send_len, recv_len, len;
+       bflush = false;
+       send_len = ch347_swd_context.send_len;
+       recv_len = ch347_swd_context.need_recv_len;
+       do {
+               if (cmd & SWD_CMD_RNW) {
+                       len = 1 + 1 + 1 + 1; /* 0xA2 + len + rev + cmd */
+                       if (send_len + len > CH347_MAX_SEND_BUF)
+                               break;
+                       send_len += len;
+                       len = 1 + 1 + 4 + 1;
+                       /* 0xA2 + 1byte(3bit ack) +  4byte(data) +
+                          1byte(1bit parity+1bit trn) */
+                       if (recv_len + len > CH347_MAX_RECV_BUF)
+                               break;
+                       recv_len += len;
+               } else {                         /* write reg */
+                       len = 1 + 1 + 1 + 1 + 4 + 1;
+                       /* 0xA0 + len + rev  + cmd +data + parity */
+                       if (send_len + len > CH347_MAX_SEND_BUF)
+                               break;
+                       send_len += len;
+                       len = 1 + 1; /* 0xA0 + 1byte(3bit ack) */
+                       if (recv_len + len > CH347_MAX_RECV_BUF)
+                               break;
+                       recv_len += len;
+               }
+               if (cmd & SWD_CMD_APNDP) {
+                       len = 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8);
+                       /* 0xA1 + Len  + rev  + n byte(delay) */
+                       if (send_len + len > CH347_MAX_SEND_BUF)
+                               break;
+                       len = 1; /* 0xA1 */
+                       if ((recv_len + len) > CH347_MAX_RECV_BUF)
+                               break;
+               }
+               /* swd packet requests */
+               bflush = true;
+       } while (false);
+       return bflush;
+}
+static void ch347_swd_send_idle(unsigned int ap_delay_clk)
+{
+       PCH347_SWD_IO pswd_io;
+       pswd_io = ch347_get_one_swd_io();
+       if (!pswd_io) {
+               ch347_swd_run_queue();
+               pswd_io = ch347_get_one_swd_io();
+               if (!pswd_io) {
+                       LOG_DEBUG("ch347_swd_queue_cmd error ");
+                       ch347_swd_context.queued_retval = ERROR_FAIL;
+                       return;
+               }
+       }
+       ch347_wrtie_spec_seq(NULL, ap_delay_clk);
+       list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head);
+}
+static void ch347_swd_queue_cmd(unsigned char cmd, unsigned int *dst, unsigned 
int data,
+                               unsigned int ap_delay_clk)
+{
+       PCH347_SWD_IO pswd_io;
+       if (ap_delay_clk > 255)
+               printf("%s ap_delay_clk = %d\r\n", "ch347_swd_queue_cmd", 
ap_delay_clk);
+       if (ch347_swd_context.sent_cmd_count >= CH347_MAX_SEND_CMD)
+               ch347_swd_run_queue();
+       if (!ch347_chk_buf_size(cmd, ap_delay_clk))
+               ch347_swd_run_queue();
+       pswd_io = ch347_get_one_swd_io();
+       if (!pswd_io) {
+               ch347_swd_run_queue();
+               pswd_io = ch347_get_one_swd_io();
+               if (!pswd_io) {
+                       LOG_DEBUG("%s error ", "ch347_swd_queue_cmd");
+                       ch347_swd_context.queued_retval = ERROR_FAIL;
+                       return;
+               }
+       }
+       pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK;
+       if (pswd_io->cmd & SWD_CMD_RNW) {
+               pswd_io->usbcmd = CH347_CMD_SWD_REG_R;
+               pswd_io->dst = dst;
+               ch347_read_swd_reg(pswd_io->cmd);
+       } else {
+               pswd_io->usbcmd = CH347_CMD_SWD_REG_W;
+               pswd_io->value = data;
+               ch347_wrtie_swd_reg(pswd_io->cmd, (unsigned char *)&data,
+                                   parity_u32(data));
+       }
+       ch347_swd_context.sent_cmd_count++;
+       list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head);
+       /* Insert idle cycles after AP accesses to avoid WAIT */
+       if (cmd & SWD_CMD_APNDP) {
+               if (ap_delay_clk == 0)
+                       printf("ap_delay_clk == 0");
+               ch347_swd_send_idle(ap_delay_clk);
+       }
+}
+static int ch347_swd_switch_seq(enum swd_special_seq seq)
+{
+       printf("%s %d \r\n", "ch347_swd_switch_seq", seq);
+       switch (seq) {
+       case LINE_RESET:
+               LOG_DEBUG("SWD line reset");
+               return ch347_swd_switch_out(seq, swd_seq_line_reset,
+                                           swd_seq_line_reset_len);
+       case JTAG_TO_SWD:
+               LOG_DEBUG("JTAG-to-SWD");
+               return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd,
+                                           swd_seq_jtag_to_swd_len);
+       case JTAG_TO_DORMANT:
+               LOG_DEBUG("JTAG-to-DORMANT");
+               return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant,
+                                           swd_seq_jtag_to_dormant_len);
+       case SWD_TO_JTAG:
+               LOG_DEBUG("SWD-to-JTAG");
+               return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag,
+                                           swd_seq_swd_to_jtag_len);
+       case SWD_TO_DORMANT:
+               LOG_DEBUG("SWD-to-DORMANT");
+               return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant,
+                                           swd_seq_swd_to_dormant_len);
+       case DORMANT_TO_SWD:
+               LOG_DEBUG("DORMANT-to-SWD");
+               return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd,
+                                           swd_seq_dormant_to_swd_len);
+       case DORMANT_TO_JTAG:
+               LOG_DEBUG("DORMANT-to-JTAG");
+               return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag,
+                                           swd_seq_dormant_to_jtag_len);
+       default:
+               LOG_ERROR("Sequence %d not supported", seq);
+               return ERROR_FAIL;
+       }
+}
+static void ch347_swd_read_reg(unsigned char cmd, unsigned int *value,
+                              unsigned int ap_delay_clk)
+{
+       assert(cmd & SWD_CMD_RNW);
+       ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
+}
+static void ch347_swd_write_reg(unsigned char cmd, unsigned int value,
+                               unsigned int ap_delay_clk)
+{
+       assert(!(cmd & SWD_CMD_RNW));
+       ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
+}
+static int ch347_swd_run_queue(void)
+{
+       LOG_DEBUG_IO("Executing %u queued transactions",
+                    ch347_swd_context.sent_cmd_count);
+       int retval, parity;
+       struct list_head *tmp, *pos;
+       unsigned char *recv_buf;
+       unsigned int recv_len, cmds_len, data;
+       PCH347_SWD_IO pswd_io;
+       if (ch347_swd_context.queued_retval != ERROR_OK) {
+               LOG_DEBUG_IO("Skipping due to previous errors: %d",
+                            ch347_swd_context.queued_retval);
+               goto skip;
+       }
+       /* A transaction must be followed by another transaction or at least 8
+          idle cycles to ensure that data is clocked through the AP. */
+       if ((ch347_swd_context.send_len + (1 + 2 + 1)) > CH347_MAX_SEND_BUF)
+               goto skip_idle;
+       if ((ch347_swd_context.need_recv_len + 1) > CH347_MAX_RECV_BUF)
+               goto skip_idle;
+       ch347_swd_send_idle(8);
+skip_idle:
+       ch347_swd_queue_flush();
+       if (ch347_swd_context.queued_retval != ERROR_OK) {
+               LOG_ERROR("CH347 usb write/read failed %d", __LINE__);
+               goto skip;
+       }
+       recv_buf = ch347_swd_context.recv_buf;
+       recv_len = 0;
+       if (recv_buf[recv_len++] != CH347_CMD_SWD) { /* 0XE8 */
+               ch347_swd_context.queued_retval = ERROR_FAIL;
+               LOG_ERROR("CH347 usb write/read failed %d", __LINE__);
+               goto skip;
+       }
+       cmds_len = BUILD_UINT16(recv_buf[recv_len], recv_buf[recv_len + 1]);
+       recv_len += 2; /* cmds_len */
+       if ((cmds_len + CH347_CMD_HEADER) > ch347_swd_context.recv_len) {
+               ch347_swd_context.queued_retval = ERROR_FAIL;
+               LOG_ERROR("CH347 usb write/read failed %d", __LINE__);
+               goto skip;
+       }
+       list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) {
+               pswd_io = list_entry(pos, CH347_SWD_IO, list_entry);
+               if (pswd_io->usbcmd == CH347_CMD_SWD_SEQ_W) {
+                       if (recv_buf[recv_len++] != CH347_CMD_SWD_SEQ_W) {
+                               ch347_swd_context.queued_retval = ERROR_FAIL;
+                               LOG_ERROR("CH347 usb write/read failed %d",
+                                         __LINE__);
+                               goto skip;
+                       }
+               } else { /* read/write Reg */
+                       int ack;
+                       bool check_ack;
+                       /* read  Reg */
+                       if (recv_buf[recv_len] == CH347_CMD_SWD_REG_R) {
+                               recv_len++;
+                               ack = buf_get_u32(&recv_buf[recv_len++], 0, 3);
+                               /* Devices do not reply to DP_TARGETSEL write
+                                  cmd, ignore received ack */
+                               check_ack = swd_cmd_returns_ack(pswd_io->cmd);
+                               if (ack != SWD_ACK_OK && check_ack) {
+                                       ch347_swd_context.queued_retval =
+                                               swd_ack_to_error_code(ack);
+                                       LOG_ERROR("ack != SWD_ACK_OK %d",
+                                                 __LINE__);
+                                       goto skip;
+                               }
+                               if (pswd_io->cmd & SWD_CMD_RNW) {
+                                       data = buf_get_u32(&recv_buf[recv_len],
+                                                          0, 32);
+                                       parity = 
buf_get_u32(&recv_buf[recv_len], 32, 1);
+                                       if (parity != parity_u32(data)) {
+                                               LOG_ERROR("SWD Read data parity 
mismatch %d",
+                                                         __LINE__);
+                                               ch347_swd_context.queued_retval 
= ERROR_FAIL;
+                                               goto skip;
+                                       }
+                                       if (pswd_io->dst)
+                                               *pswd_io->dst = data;
+                               } else {
+                                       ch347_swd_context.queued_retval =
+                                               ERROR_FAIL;
+                                       LOG_ERROR("CH347 usb write/read failed 
%d", __LINE__);
+                                       goto skip;
+                               }
+                               recv_len += 5;
+                       } else if (recv_buf[recv_len] == CH347_CMD_SWD_REG_W) {
+                               recv_len++;
+                               ack = buf_get_u32(&recv_buf[recv_len++], 0, 3);
+                               /* Devices do not reply to DP_TARGETSEL write
+                                  cmd, ignore received ack */
+                               check_ack = swd_cmd_returns_ack(pswd_io->cmd);
+                               if (ack != SWD_ACK_OK && check_ack) {
+                                       ch347_swd_context.queued_retval =
+                                               swd_ack_to_error_code(ack);
+                                       LOG_ERROR("SWD Read data parity 
mismatch%d", __LINE__);
+                                       goto skip;
+                               }
+                       } else {
+                               ch347_swd_context.queued_retval = ERROR_FAIL;
+                               LOG_ERROR("CH347 usb write/read failed %d 
recv_len = %d",
+                                         __LINE__, recv_len);
+                               goto skip;
+                       }
+               }
+               list_del_init(&pswd_io->list_entry);
+               list_add_tail(&pswd_io->list_entry,
+                             &ch347_swd_context.free_cmd_head);
+       }
+skip:
+       if (!list_empty(&ch347_swd_context.send_cmd_head)) {
+               list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) {
+                       pswd_io = list_entry(pos, CH347_SWD_IO, list_entry);
+                       list_del_init(&pswd_io->list_entry);
+                       list_add_tail(&pswd_io->list_entry,
+                                     &ch347_swd_context.free_cmd_head);
+               }
+       }
+       /* 0xE8 + 2byte len */
+       ch347_swd_context.send_len = CH347_CMD_HEADER;
+       /* 0xE8 + 2byte len */
+       ch347_swd_context.need_recv_len = CH347_CMD_HEADER;
+       ch347_swd_context.recv_len = 0;
+       ch347_swd_context.sent_cmd_count = 0;
+       retval = ch347_swd_context.queued_retval;
+       ch347_swd_context.queued_retval = ERROR_OK;
+       return retval;
+}
+static const struct swd_driver ch347_swd = {
+       .init = ch347_swd_init,
+       .switch_seq = ch347_swd_switch_seq,
+       .read_reg = ch347_swd_read_reg,
+       .write_reg = ch347_swd_write_reg,
+       .run = ch347_swd_run_queue,
+};
+static const char *const ch347_transports[] = {"jtag", "swd", NULL};
+static struct jtag_interface ch347_interface = {
+       .supported = DEBUG_CAP_TMS_SEQ,
+       .execute_queue = ch347_execute_queue,
+};
+struct adapter_driver ch347_adapter_driver = {
+       .name = "ch347",
+       .transports = ch347_transports,
+       .commands = ch347_command_handlers,
+       .init = ch347_init,
+       .quit = ch347_quit,
+       .reset = ch347_reset,
+       .speed = ch347_speed,
+       .khz = ch347_khz,
+       .speed_div = ch347_speed_div,
+       .jtag_ops = &ch347_interface,
+       .swd_ops = &ch347_swd,
+};
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index b448851dc4..ba5c5eb2db 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -378,6 +378,7 @@ extern struct adapter_driver ep93xx_adapter_driver;
 extern struct adapter_driver esp_usb_adapter_driver;
 extern struct adapter_driver ft232r_adapter_driver;
 extern struct adapter_driver ftdi_adapter_driver;
+extern struct adapter_driver ch347_adapter_driver;
 extern struct adapter_driver gw16012_adapter_driver;
 extern struct adapter_driver hl_adapter_driver;
 extern struct adapter_driver imx_gpio_adapter_driver;
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 67f0838e39..e0cfd660cf 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -152,6 +152,9 @@ struct adapter_driver *adapter_drivers[] = {
 #endif
 #if BUILD_AM335XGPIO == 1
                &am335xgpio_adapter_driver,
+#endif
+#if BUILD_CH347 == 1
+               &ch347_adapter_driver,
 #endif
                NULL,
        };
diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c
index 284bfc9c62..fe1b83bc3e 100644
--- a/src/target/xtensa/xtensa.c
+++ b/src/target/xtensa/xtensa.c
@@ -1727,7 +1727,7 @@ int xtensa_do_step(struct target *target, int current, 
target_addr_t address, in
        xtensa_reg_val_t dbreakc[XT_WATCHPOINTS_NUM_MAX];
        xtensa_reg_val_t icountlvl, cause;
        xtensa_reg_val_t oldps, oldpc, cur_pc;
-       bool ps_lowered = false;
+       bool ps_modified = false;
 
        LOG_TARGET_DEBUG(target, "current=%d, address=" TARGET_ADDR_FMT ", 
handle_breakpoints=%i",
                current, address, handle_breakpoints);
@@ -1783,14 +1783,23 @@ int xtensa_do_step(struct target *target, int current, 
target_addr_t address, in
         * RFI >= DBGLEVEL.
         */
        if (xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF) {
-               if (!xtensa->core_config->high_irq.enabled) {
-                       LOG_TARGET_WARNING(
-                               target,
-                               "disabling IRQs while stepping is not 
implemented w/o high prio IRQs option!");
-                       return ERROR_FAIL;
+               if (xtensa->core_config->core_type == XT_LX) {
+                       if (!xtensa->core_config->high_irq.enabled) {
+                               LOG_TARGET_WARNING(target,
+                                               "disabling IRQs while stepping 
is not implemented w/o high prio IRQs option!");
+                               return ERROR_FAIL;
+                       }
+                       /* Update ICOUNTLEVEL accordingly */
+                       icountlvl = MIN((oldps & 0xF) + 1, 
xtensa->core_config->debug.irq_level);
+               } else {
+                       /* Xtensa NX does not have the ICOUNTLEVEL feature 
present in Xtensa LX
+                        * and instead disable interrupts while stepping. This 
could change
+                        * the timing of the system while under debug */
+                       xtensa_reg_val_t newps = oldps | XT_PS_DI_MSK;
+                       xtensa_reg_set(target, XT_REG_IDX_PS, newps);
+                       icountlvl = xtensa->core_config->debug.irq_level;
+                       ps_modified = true;
                }
-               /* Update ICOUNTLEVEL accordingly */
-               icountlvl = MIN((oldps & 0xF) + 1, 
xtensa->core_config->debug.irq_level);
        } else {
                icountlvl = xtensa->core_config->debug.irq_level;
        }
@@ -1815,7 +1824,7 @@ int xtensa_do_step(struct target *target, int current, 
target_addr_t address, in
                xtensa_cause_clear(target);     /* so we don't recurse into the 
same routine */
        if (xtensa->core_config->core_type == XT_LX && ((oldps & 0xf) >= 
icountlvl)) {
                /* Lower interrupt level to allow stepping, but flag 
eps[dbglvl] to be restored */
-               ps_lowered = true;
+               ps_modified = true;
                uint32_t newps = (oldps & ~0xf) | (icountlvl - 1);
                xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps);
                LOG_TARGET_DEBUG(target,
@@ -1916,11 +1925,12 @@ int xtensa_do_step(struct target *target, int current, 
target_addr_t address, in
        }
 
        /* Restore int level */
-       if (ps_lowered) {
+       if (ps_modified) {
                LOG_DEBUG("Restoring %s after stepping: 0x%08" PRIx32,
-                       
xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name,
-                       oldps);
-               xtensa_reg_set(target, xtensa->eps_dbglevel_idx, oldps);
+                       
xtensa->core_cache->reg_list[(xtensa->core_config->core_type == XT_LX) ?
+                               xtensa->eps_dbglevel_idx : XT_REG_IDX_PS].name, 
oldps);
+               xtensa_reg_set(target, (xtensa->core_config->core_type == 
XT_LX) ?
+                       xtensa->eps_dbglevel_idx : XT_REG_IDX_PS, oldps);
        }
 
        /* write ICOUNTLEVEL back to zero */
@@ -4191,11 +4201,6 @@ COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct 
xtensa *xtensa)
                return ERROR_OK;
        }
 
-       if (xtensa->core_config->core_type == XT_NX) {
-               command_print(CMD, "ERROR: ISR step mode only supported on 
Xtensa LX");
-               return ERROR_FAIL;
-       }
-
        /* Masking is ON -> interrupts during stepping are OFF, and vice versa 
*/
        if (!strcasecmp(CMD_ARGV[0], "off"))
                state = XT_STEPPING_ISR_ON;
diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h
index 1d56f83682..419277675c 100644
--- a/src/target/xtensa/xtensa.h
+++ b/src/target/xtensa/xtensa.h
@@ -45,6 +45,7 @@
 
 /* PS register bits (NX) */
 #define XT_PS_DIEXC_MSK                         BIT(2)
+#define XT_PS_DI_MSK                            BIT(3)
 
 /* MS register bits (NX) */
 #define XT_MS_DE_MSK                            BIT(5)

-- 

Reply via email to