This is an automated email from Gerrit.

"Conor Paxton <conor.pax...@microchip.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8552

-- gerrit

commit b5dd81b547f9d488891c2cd825c6258814431448
Author: Conor Paxton <conor.pax...@microchip.com>
Date:   Mon May 20 19:05:32 2024 +0100

    jtag: drivers: add microchip embedded flashpro6 support
    
    This patch adds support for Microchip's embedded FlashPro6 which can be
    found on Microchip's PolarFire SoC Icicle Kit and Video Kit
    
    Change-Id: I006159609a56f70b1043f34c196d75292483f69d
    Signed-off-by: Tommy Murphy <tommy_mur...@hotmail.com>
    Signed-off-by: Anton Krug <anton.k...@gmail.com>
    Signed-off-by: Daire McNamara <daire.mcnam...@microchip.com>
    Signed-off-by: Matteo Bonicolini <matteo.bonicol...@microchip.com>
    Signed-off-by: Conor Paxton <conor.pax...@microchip.com>

diff --git a/configure.ac b/configure.ac
index da1ad35c7c..cbd2ecedb2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,6 +351,10 @@ AC_ARG_ENABLE([microchip_fp6],
   AS_HELP_STRING([--enable-microchip-fp6], [Enable building support for 
Microchip FlashPro6 Programmer]),
   [build_microchip_fp6=$enableval], [build_microchip_fp6=no])
 
+AC_ARG_ENABLE([microchip_efp6],
+  AS_HELP_STRING([--enable-microchip-efp6], [Enable building support for 
Microchip embedded FlashPro6 Programmer]),
+  [build_microchip_efp6=$enableval], [build_microchip_efp6=no])
+
 AS_CASE([$host_os],
   [linux*], [
     is_linux=yes
@@ -631,6 +635,13 @@ AS_IF([test "x$build_microchip_fp6" = "xyes"], [
   AC_DEFINE([BUILD_MICROCHIP_FP6], [0], [0 if you don't the Microchip 
FlashPro6 driver.])
 ])
 
+AS_IF([test "x$build_microchip_efp6" = "xyes"], [
+  build_microchip_efp6=yes
+  AC_DEFINE([BUILD_MICROCHIP_EFP6], [1], [1 if you want the Microchip 
emebedded FlashPro6 driver.])
+], [
+  AC_DEFINE([BUILD_MICROCHIP_EFP6], [0], [0 if you don't the Microchip 
embedded FlashPro6 driver.])
+])
+
 PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [
        use_libusb1=yes
        AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x])
@@ -794,6 +805,7 @@ 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([MICROCHIP_FP6], [test "x$build_microchip_fp6" = "xyes"])
+AM_CONDITIONAL([MICROCHIP_EFP6], [test "x$build_microchip_efp6" = "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/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index fec05e5f2c..3ef4d4f6c3 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -207,6 +207,9 @@ endif
 if MICROCHIP_FP6
 DRIVERFILES += %D%/mchp_fp6.c
 endif
+if MICROCHIP_EFP6
+DRIVERFILES += %D%/mchp_efp6.c
+endif
 
 DRIVERHEADERS = \
        %D%/bitbang.h \
@@ -226,4 +229,5 @@ DRIVERHEADERS = \
        %D%/versaloon/versaloon_include.h \
        %D%/versaloon/versaloon_internal.h \
        %D%/mchp_fp.h \
-       %D%/mchp_fp6.h
+       %D%/mchp_fp6.h \
+       %D%/mchp_efp6.h
diff --git a/src/jtag/drivers/mchp_efp6.c b/src/jtag/drivers/mchp_efp6.c
new file mode 100644
index 0000000000..cd77ebf358
--- /dev/null
+++ b/src/jtag/drivers/mchp_efp6.c
@@ -0,0 +1,681 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2024 by Microchip Inc.                                  *
+ *   matteo.bonicol...@microchip.com                                       *
+ ***************************************************************************/
+
+#include <hidapi.h>
+#include <jtag/interface.h>
+
+#include "mchp_efp6.h"
+#include "helper/log.h"
+
+static int quitting;
+
+static hid_device *efp6_handle;
+
+static wchar_t serial_number[EFP6_MAX_SERIAL_STRING];
+static char specific_serial_number[EFP6_MAX_SERIAL_STRING];
+static bool specified_serial_number;
+
+__attribute__((aligned(8)))
+static uint8_t usb_in_buffer[FP_MAX_USB_BUFFER_BYTE_SIZE];
+
+__attribute__((aligned(8)))
+static uint8_t usb_out_buffer[FP_MAX_USB_BUFFER_BYTE_SIZE];
+
+static uint8_t packets_in_buffer;
+static uint32_t bytes_in_buffer = EFP6_PACKET_OFFSET;
+
+__attribute__((always_inline)) inline
+static void write16(uint8_t *buf, uint16_t val)
+{
+       uint8_t *ptr = buf;
+
+       *ptr++ = val & 0xff;
+       *ptr = val >> 8;
+}
+
+__attribute__((always_inline)) inline
+static void add_usb_packet_header(uint16_t packet_type, uint32_t 
target_address, uint32_t packet_length)
+{
+       uint8_t *ptr = &usb_in_buffer[bytes_in_buffer];
+
+       write16(ptr, FP_PACKET_START_CODE);
+       ptr += 2;
+
+       write16(ptr, packet_type);
+       ptr += 2;
+
+       write16(ptr, target_address >> 16);
+       ptr += 2;
+       write16(ptr, target_address);
+       ptr += 2;
+
+       write16(ptr, packet_length >> 16);
+       ptr += 2;
+       write16(ptr, packet_length);
+
+       /* Skipping CRC - the firmware/IP ignores it */
+}
+
+__attribute__((always_inline)) inline
+static void add_usb_packet_header_simpler(uint16_t packet_type, uint32_t 
packet_length)
+{
+       uint8_t *ptr = &usb_in_buffer[bytes_in_buffer];
+
+       /*
+        * Similar as add_usb_packet_header, but even more simplified, it 
assumes:
+        * - the target address is 0
+        * - the length is under 65536
+        * - the CRC is ignored in the firmware/IP and doesn't have to be set
+        * - that we correctly zeroized the buffer previously and all the 
skipped writes will have 0 in the buffer anyway
+        */
+       write16(ptr, FP_PACKET_START_CODE);
+       ptr += 2;
+
+       write16(ptr, packet_type);
+       ptr += 8;
+
+       /* Skipping high 16-bits of the 32-bit target address */
+       /* Skipping low 16-bits of the 32-bit target address */
+
+       /* Skipping High 16-bits of the 32-bit packet length */
+       write16(ptr, packet_length);
+
+       /* Skipping CRC - the firmware/IP ignores it */
+}
+
+__attribute__((always_inline)) inline
+static int flush_usb_buffer(void)
+{
+       int err;
+
+       /*
+        * __MINGW32__ is detecting the Windows builds, for Windows it uses 
separate slightly bigger buffer
+        * so it can prepone the payload with one 0. In essence the REPORT ID 
is optional, but not on Windows
+        * so it has to be set to 0 to skip it and we need to send 1024 payload 
on Windows we have to send 1025
+        * instead. Cleaner it would be to put it into hidapi and then treat 
the API the same and I did it for
+        * a moment and the build can be changed to use different fork, but 
then having to maintain it could
+        * be hassle so I reverted to a ugly fix on the host side done here, 
instead of having it the library.
+        * There are numerous issues around the 0 on Windows on the signal11 
repository, and it looks like
+        * the libusb (maintained fork) shares the same problem
+        * https://stackoverflow.com/a/31668028/4535300
+        */
+       #ifdef __MINGW32__
+       static uint8_t usb_in_buffer_reportid[FP_MAX_USB_BUFFER_BYTE_SIZE + 1];
+
+       usb_in_buffer_reportid[0] = 0;
+       #endif
+
+       usb_in_buffer[0] = packets_in_buffer;
+
+       if (quitting)
+               return ERROR_OK;
+
+       #ifdef __MINGW32__
+       memcpy(usb_in_buffer_reportid + 1, usb_in_buffer, 
FP_MAX_USB_BUFFER_BYTE_SIZE);
+       err = hid_write(efp6_handle, usb_in_buffer_reportid, 
FP_MAX_USB_BUFFER_BYTE_SIZE + 1);
+       #else
+       err = hid_write(efp6_handle, usb_in_buffer, 
FP_MAX_USB_BUFFER_BYTE_SIZE);
+       #endif
+
+       if (err < 0) {
+               LOG_ERROR("Embedded FlashPro6 failed to send the data.");
+               LOG_ERROR("Programmer device reset is required.  Err = %d 
(%ls)",
+                                                                               
                err, hid_error(efp6_handle));
+               exit(0);
+       }
+       memset(usb_in_buffer, 0, bytes_in_buffer);
+
+       err = hid_read_timeout(efp6_handle, usb_out_buffer, 
FP_MAX_USB_BUFFER_BYTE_SIZE, FP_READ_TIMEOUT);
+       if (err < (int)FP_MAX_USB_BUFFER_BYTE_SIZE) {
+               LOG_ERROR("Failed to read data from USB buffer.");
+               LOG_ERROR("Programmer reset is required.  Err = %d (%ls)", err, 
hid_error(efp6_handle));
+               exit(0);
+       }
+
+       bytes_in_buffer = EFP6_PACKET_OFFSET;
+       packets_in_buffer = 0;
+
+       return ERROR_OK;
+}
+
+__attribute__((always_inline)) inline
+static void add_packet_to_usb_buffer(uint16_t opcode, const uint8_t *buf, 
uint32_t packet_length,
+                                                                               
                uint32_t num_padding_bytes, uint32_t target_address)
+{
+       if (buf)
+               memcpy(&usb_in_buffer[bytes_in_buffer + 
EFP6_PACKET_HEADER_PREAMBLE_LENGTH], buf, packet_length);
+
+       if (target_address != 0)
+               add_usb_packet_header(opcode, target_address, packet_length + 
num_padding_bytes);
+       else
+               add_usb_packet_header_simpler(opcode, packet_length + 
num_padding_bytes);
+
+       bytes_in_buffer += EFP6_PACKET_HEADER_TOTAL_LENGTH + packet_length + 
num_padding_bytes;
+
+       packets_in_buffer++;
+}
+
+__attribute__((always_inline)) inline
+static int construct_and_send_packet(uint16_t opcode, uint8_t const *buf, 
uint32_t packet_length,
+                                                                               
                                                                uint32_t 
target_address)
+{
+       add_packet_to_usb_buffer(opcode, buf, packet_length, 0, target_address);
+       return flush_usb_buffer();
+}
+
+__attribute__((always_inline)) inline
+static int retrieve_data(uint8_t *buf, uint32_t bit_length)
+{
+       int err;
+       uint32_t byte_length;
+
+       byte_length = (bit_length + 7) / 8;
+
+       err = construct_and_send_packet(READ_TDO_BUFFER_COMMAND_OPCODE, NULL, 
0, 0);
+
+       if (err)
+               return err;
+
+       memcpy(buf, usb_out_buffer, byte_length);
+
+       return err;
+}
+
+static int mchp_efp6_enumerate(const char *partial_port_name)
+{
+       struct hid_device_info *devs;
+       uint32_t num_found_devices = 0;
+       size_t port_string_size = 0;
+       wchar_t efp6port[EFP6_MAX_SERIAL_STRING];
+
+       if (partial_port_name) {
+               port_string_size = strlen(partial_port_name);
+               mbstowcs(efp6port, partial_port_name, port_string_size + 1);
+       }
+
+       if (hid_init() != 0) {
+               LOG_ERROR("unable to open HIDAPI");
+               return ERROR_FAIL;
+       }
+
+       devs = hid_enumerate(EFP6_VID, EFP6_REV_A_PID);
+       for (struct hid_device_info *cur_dev = devs; cur_dev; cur_dev = 
cur_dev->next) {
+               LOG_INFO("Embedded FlashPro6 Rev B found (%04x:%04x %ls %ls 
%ls)",
+                       cur_dev->vendor_id, cur_dev->product_id,
+                       cur_dev->manufacturer_string, cur_dev->product_string,
+                       cur_dev->serial_number);
+               LOG_WARNING("Please upgrade firmware to Rev B");
+               exit(0);
+       }
+       hid_free_enumeration(devs);
+
+       devs = hid_enumerate(EFP6_VID, EFP6_REV_B_PID);
+       for (struct hid_device_info *cur_dev = devs; cur_dev; cur_dev = 
cur_dev->next) {
+               LOG_INFO("Embedded FlashPro6 Rev B found (%04x:%04x %ls %ls 
%ls)",
+                       cur_dev->vendor_id, cur_dev->product_id,
+                       cur_dev->manufacturer_string, cur_dev->product_string,
+                       cur_dev->serial_number);
+
+               if (port_string_size == 0) {
+                       num_found_devices++;
+                       wcsncpy(serial_number, cur_dev->serial_number, 
EFP6_MAX_SERIAL_STRING);
+               } else {
+                       if (wcsncmp(cur_dev->serial_number, efp6port, 
port_string_size) == 0) {
+                               num_found_devices++;
+                               wcsncpy(serial_number, cur_dev->serial_number, 
EFP6_MAX_SERIAL_STRING);
+                               LOG_DEBUG("The device at %s with port %d 
matched with the port checker",
+                                                                               
                cur_dev->path, *cur_dev->serial_number);
+                       } else {
+                               LOG_DEBUG("The device at %s with port %d will 
be ignored "
+                                                       "because it didn't 
match the port checker",
+                                                               cur_dev->path, 
*cur_dev->serial_number);
+                       }
+               }
+       }
+
+       hid_free_enumeration(devs);
+
+       if (num_found_devices == 0)
+               LOG_INFO("No Embedded FlashPro6 devices found");
+
+       return num_found_devices;
+}
+
+static int mchp_efp6_open(void)
+{
+       int err;
+
+       memset(usb_in_buffer, 0, FP_MAX_USB_BUFFER_BYTE_SIZE);
+       memset(usb_out_buffer, 0, FP_MAX_USB_BUFFER_BYTE_SIZE);
+
+       efp6_handle = hid_open(EFP6_VID, EFP6_REV_B_PID, serial_number);
+       if (!efp6_handle) {
+               LOG_ERROR("Unable to open Embedded FlashPro6 device");
+               return EFP6_RESPONSE_DEVICE_OPEN_ERROR;
+       }
+
+       err = hid_set_nonblocking(efp6_handle, 0);
+       if (err) {
+               LOG_ERROR("Embedded FlashPro6 hid_set_nonblocking failed: %d 
(%ls)", err,
+                                                                               
                                        hid_error(efp6_handle));
+               return err;
+       }
+
+       err = mchp_efp6_get_cm3_version();
+       if (err) {
+               LOG_ERROR("Embedded FlashPro6 get_cm3_version failed (%d)", 
err);
+               return err;
+       }
+
+       err = mchp_efp6_enable_jtag_port();
+       if (err) {
+               LOG_ERROR("Embedded FlashPro6 enable Jtag port failed (%d)", 
err);
+               return err;
+       }
+
+       mchp_efp6_set_led(EFP6_SOLID_GREEN);
+
+       return ERROR_OK;
+}
+
+static int mchp_efp6_quit(void)
+{
+       quitting = 1;
+       LOG_INFO("Embedded FlashPro6 closing the device");
+
+       mchp_efp6_disable_jtag_port();
+       mchp_efp6_set_led(EFP6_OFF);
+
+       hid_close(efp6_handle);
+       hid_exit();
+
+       return ERROR_OK;
+}
+
+static int mchp_efp6_get_cm3_version(void)
+{
+       int err;
+
+       err = construct_and_send_packet(EFP6_CM3_FW_VERSION_OPCODE, NULL, 0, 0);
+       if (err)
+               LOG_ERROR("Embedded FlashPro6 failed to read firmware version 
number (%d)", err);
+       else
+               LOG_INFO("Embedded FlashPro6 CM3 firmware version: %X.%X",
+                                                       usb_out_buffer[1], 
usb_out_buffer[0]);
+
+       return err;
+}
+
+static int mchp_efp6_speed(int32_t tck_freq)
+{
+       uint8_t payload_buf[PAYLOAD_ATOMIC_PACKET_LENGTH] = { 0 };
+       const int default_tck_mhz = 12;
+       int err;
+
+       if (tck_freq <= 0) {
+               LOG_WARNING("Embedded FlashPro6 TCK frequency is set to 0. "
+               "use valid frequency of %dMHz instead", default_tck_mhz);
+               tck_freq = default_tck_mhz * 1000000;
+       }
+
+       tck_freq = tck_freq / 1000000;
+
+       if (tck_freq < 4 || tck_freq > 20) {
+               LOG_WARNING("Embedded FlashPro6 frequency range is 4 MHz - 20 
MHz. "
+               "Setting frequency to %dMHz", default_tck_mhz);
+               tck_freq = default_tck_mhz;
+       }
+
+       payload_buf[0] = FP_SET_TCK_FREQUENCY;
+       payload_buf[1] = tck_freq;
+
+       err = construct_and_send_packet(SEND_PACKET_OPCODE, payload_buf, 
PAYLOAD_ATOMIC_PACKET_LENGTH,
+                                                                               
                                                                
FP_TARGET_FREQUENCY_ADDRESS);
+       if (err)
+               return err;
+
+       return construct_and_send_packet(FREQUENCY_INTERRUPT_OPCODE, NULL, 0, 
0);
+}
+
+static int mchp_efp6_enable_jtag_port(void)
+{
+       return construct_and_send_packet(ENABLE_JTAG_PORT_OPCODE, NULL, 0, 0);
+}
+
+static int mchp_efp6_disable_jtag_port(void)
+{
+       return construct_and_send_packet(DISABLE_JTAG_PORT_OPCODE, NULL, 0, 0);
+}
+
+static int mchp_efp6_execute_reset(struct reset_command const *cmd)
+{
+       uint8_t payload_buf[2] = { 0 };
+
+       if (!cmd->trst)
+               payload_buf[0] = EFP6_TRSTB_BIT;
+
+       return construct_and_send_packet(SET_JTAG_PINS_OPCODE, payload_buf,
+                                                               
ATOMIC_JTAG_OPERATION_PACKET_LENGTH, 0);
+}
+
+static int mchp_efp6_set_led(uint8_t status)
+{
+       int err;
+       uint8_t payload_buf[2] = { 0 };
+
+       payload_buf[0] = status;
+
+       err = construct_and_send_packet(TURN_ACTIVITY_LED_OFF_OPCODE, NULL, 0, 
0);
+       if (err)
+               return err;
+
+       if (status != EFP6_OFF)
+               err = construct_and_send_packet(TURN_ACTIVITY_LED_ON_OPCODE, 
payload_buf,
+                                                                               
        ATOMIC_JTAG_OPERATION_PACKET_LENGTH, 0);
+
+       return err;
+}
+
+static int mchp_efp6_jtag_go_to_state_raw(int state)
+{
+       int err = ERROR_OK;
+       uint8_t payload_buf[ATOMIC_JTAG_OPERATION_PACKET_LENGTH];
+
+       write16(payload_buf, state);
+
+       add_packet_to_usb_buffer(JTAG_ATOMIC_OPCODE, payload_buf, 
ATOMIC_JTAG_OPERATION_PACKET_LENGTH,
+                                                                               
                                                                                
                        0, 0);
+
+       if (state == TAP_RESET)
+               err = flush_usb_buffer();
+
+       return err;
+}
+
+static int mchp_efp6_execute_statemove(struct statemove_command const *cmd)
+{
+       int err = ERROR_OK;
+       uint8_t payload_buf[ATOMIC_JTAG_OPERATION_PACKET_LENGTH];
+
+       write16(payload_buf, cmd->end_state);
+
+       add_packet_to_usb_buffer(JTAG_ATOMIC_OPCODE, payload_buf, 
ATOMIC_JTAG_OPERATION_PACKET_LENGTH,
+                                                                               
                                                                                
                        0, 0);
+
+       if (cmd->end_state == TAP_RESET)
+               err = flush_usb_buffer();
+
+       return err;
+}
+
+static int mchp_efp6_execute_runtest(struct runtest_command const *cmd)
+{
+       if (cmd->end_state != TAP_IDLE)
+               LOG_ERROR("Embedded FlashPro6 execute run-test state only "
+                               "implemented with TAP_IDLE end-state");
+
+       for (unsigned int i = 0; i < cmd->num_cycles; i++)
+               mchp_efp6_jtag_go_to_state_raw(TAP_IDLE);
+
+       return mchp_efp6_jtag_go_to_state_raw(TAP_IDLE);
+}
+
+static int mchp_efp6_ir_scan(uint32_t bit_length, const uint8_t *out, uint8_t 
*in,
+                                                                               
                                                uint16_t end_state)
+{
+       int err = ERROR_OK;
+
+       __attribute__((aligned(8)))
+       static struct efp6_ir_scan full_scan = {
+               .set_len = {
+                       .packet_start = FP_PACKET_START_CODE,
+                       .packet_type = SET_SHIFT_IR_DR_BIT_LENGTH_OPCODE,
+                       .address = 0,
+                       .len_high = 0,
+                       .len_low = ATOMIC_JTAG_OPERATION_PACKET_LENGTH,
+                       .data[0] = 0,
+                       .data[1] = 0,
+                       .crc = 0
+               },
+               .data = {
+                       .packet_start = FP_PACKET_START_CODE,
+                       .packet_type = SHIFT_DATA_FROM_REGISTER_OPCODE,
+                       .address = 0,
+                       .len_high = 0,
+                       .len_low = ATOMIC_JTAG_OPERATION_PACKET_LENGTH,
+                       .data[0] = 0,
+                       .data[1] = 0,
+                       .crc = 0
+               },
+               .shift = {
+                       .packet_start = FP_PACKET_START_CODE,
+                       .packet_type = JTAG_ATOMIC_OPCODE,
+                       .address = 0,
+                       .len_high = 0,
+                       .len_low = ATOMIC_JTAG_OPERATION_PACKET_LENGTH,
+                       .data[0] = TAP_IRSHIFT,
+                       .data[1] = 0,
+                       .crc = 0
+               },
+               .end_state = {
+                       .packet_start = FP_PACKET_START_CODE,
+                       .packet_type = JTAG_ATOMIC_OPCODE,
+                       .address = 0,
+                       .len_high = 0,
+                       .len_low = ATOMIC_JTAG_OPERATION_PACKET_LENGTH,
+                       .data[0] = 0,
+                       .data[1] = 0,
+                       .crc = 0
+               }
+       };
+
+       full_scan.set_len.data[0] = bit_length;
+       full_scan.data.data[0] = out[0];
+       full_scan.data.data[1] = out[1];
+       full_scan.end_state.data[0] = end_state;
+
+       memcpy(&usb_in_buffer[bytes_in_buffer], (uint8_t *)&full_scan, 
sizeof(full_scan));
+
+       bytes_in_buffer += sizeof(full_scan);
+       packets_in_buffer += 4;
+
+       if (end_state == TAP_RESET)
+               err = flush_usb_buffer();
+
+       if (in && err == ERROR_OK)
+               err = retrieve_data(in, bit_length);
+
+       return err;
+}
+
+static int mchp_efp6_dr_scan(uint32_t bit_length, const uint8_t *out, uint8_t 
*in,
+                                                                               
                                                uint16_t end_state)
+{
+       int err = ERROR_OK;
+       uint8_t payload_buf[ATOMIC_JTAG_OPERATION_PACKET_LENGTH];
+       uint32_t bytes_to_transmit;
+       uint32_t padding_bytes;
+
+       write16(payload_buf, bit_length);
+       add_packet_to_usb_buffer(SET_SHIFT_IR_DR_BIT_LENGTH_OPCODE, payload_buf,
+                                                               
ATOMIC_JTAG_OPERATION_PACKET_LENGTH, 0, 0);
+
+       padding_bytes = 0;
+       if (bit_length > 16) {
+               bytes_to_transmit = (uint32_t)((bit_length + 7) / 8);
+               if (bytes_to_transmit % 16)
+                       padding_bytes = (16 - bytes_to_transmit % 16);
+
+               add_packet_to_usb_buffer(SHIFT_DATA_FROM_DDR_OPCODE, out, 
bytes_to_transmit, padding_bytes,
+                                                                               
                                                                                
                                0);
+
+               if (bytes_in_buffer % EFP6_PACKET_OFFSET)
+                       bytes_in_buffer += (EFP6_PACKET_OFFSET - 
bytes_in_buffer % EFP6_PACKET_OFFSET);
+       } else {
+               add_packet_to_usb_buffer(SHIFT_DATA_FROM_REGISTER_OPCODE, out, 
2, 0, 0);
+       }
+
+       payload_buf[0] = TAP_DRSHIFT;
+       payload_buf[1] = 0;
+       add_packet_to_usb_buffer(JTAG_ATOMIC_OPCODE, payload_buf,
+                               ATOMIC_JTAG_OPERATION_PACKET_LENGTH, 0, 0);
+
+       err = mchp_efp6_jtag_go_to_state_raw(end_state);
+
+       if (in && err == ERROR_OK)
+               err = retrieve_data(in, bit_length);
+
+       return err;
+}
+
+static int mchp_efp6_execute_scan(struct scan_command *cmd)
+{
+       int err;
+
+       if (cmd->num_fields > 1) {
+               LOG_ERROR("Execute scan is implemented only with one field but 
this request has %d fields",
+                                                                               
                                                                                
cmd->num_fields);
+               return ERROR_FAIL;
+       }
+
+       if (cmd->ir_scan)
+               err = mchp_efp6_ir_scan(cmd->fields[0].num_bits, 
cmd->fields[0].out_value,
+                                                                               
cmd->fields[0].in_value, cmd->end_state);
+       else
+               err = mchp_efp6_dr_scan(cmd->fields[0].num_bits, 
cmd->fields[0].out_value,
+                                                                               
cmd->fields[0].in_value, cmd->end_state);
+
+       return err;
+}
+
+static int mchp_efp6_speed_div(int speed, int *khz)
+{
+       *khz = speed / HZ_PER_KHZ;
+
+       return ERROR_OK;
+}
+
+static int mchp_efp6_khz(int khz, int *jtag_speed)
+{
+       *jtag_speed = khz * HZ_PER_KHZ;
+
+       return ERROR_OK;
+}
+
+static int mchp_efp6_execute_command(struct jtag_command *cmd)
+{
+       switch (cmd->type) {
+       case JTAG_SCAN:
+               return mchp_efp6_execute_scan(cmd->cmd.scan);
+
+       case JTAG_RUNTEST:
+               return mchp_efp6_execute_runtest(cmd->cmd.runtest);
+
+       case JTAG_RESET:
+               return mchp_efp6_execute_reset(cmd->cmd.reset);
+
+       case JTAG_TLR_RESET:
+               return mchp_efp6_execute_statemove(cmd->cmd.statemove);
+
+       default:
+               break;
+       }
+
+       return ERROR_OK;
+}
+
+static int mchp_efp6_execute_queue(struct jtag_command *cmd_queue)
+{
+       struct jtag_command *cmd = cmd_queue;
+
+       while (cmd) {
+               if (mchp_efp6_execute_command(cmd))
+                       return ERROR_COMMAND_CLOSE_CONNECTION;
+
+               cmd = cmd->next;
+       }
+
+       return ERROR_OK;
+}
+
+static int mchp_efp6_init(void)
+{
+       int err;
+
+       if (specified_serial_number)
+               err = mchp_efp6_enumerate(specific_serial_number);
+       else
+               err = mchp_efp6_enumerate(0);
+
+       if (err < 0)
+               return ERROR_FAIL;
+
+       return mchp_efp6_open();
+}
+
+static int mchp_efp6_reset(int trst, int srst)
+{
+       uint8_t payload_buf[2] = { 0x0, 0x0 };
+
+       if (!trst)
+               payload_buf[0] = EFP6_TRSTB_BIT;
+
+       return construct_and_send_packet(SET_JTAG_PINS_OPCODE, payload_buf,
+                                                               
ATOMIC_JTAG_OPERATION_PACKET_LENGTH, 0);
+}
+
+COMMAND_HANDLER(mchp_efp6_handle_serial_num)
+{
+       if (CMD_ARGC == 1) {
+               memcpy(specific_serial_number, CMD_ARGV[0], 126);
+               specified_serial_number = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration mchp_efp6_subcommand_handlers[] = {
+       {
+               .name = "serial",
+               .handler = mchp_efp6_handle_serial_num,
+               .mode = COMMAND_CONFIG,
+               .help = "SERIAL_NUM to locate unique Embedded FP6",
+               .usage = "[SERIAL_NUM]",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration mchp_efp6_command_handlers[] = {
+       {
+               .name = "mchp_efp6",
+               .mode = COMMAND_ANY,
+               .help = "perform mchp_efp6 management",
+               .chain = mchp_efp6_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const char * const mchp_efp6_transports[] = { "jtag", NULL };
+
+static struct jtag_interface mchp_efp6_interface = {
+       .supported = 0, /* Don't support DEBUG_CAP_TMS_SEQ */
+       .execute_queue = mchp_efp6_execute_queue,
+};
+
+struct adapter_driver mchp_efp6_adapter_driver = {
+       .name = "microchip-efp6",
+       .commands = mchp_efp6_command_handlers,
+       .transports = mchp_efp6_transports,
+       .init = mchp_efp6_init,
+       .quit = mchp_efp6_quit,
+       .reset = mchp_efp6_reset,
+       .speed = mchp_efp6_speed,
+       .khz = mchp_efp6_khz,
+       .speed_div = mchp_efp6_speed_div,
+       .jtag_ops = &mchp_efp6_interface,
+};
diff --git a/src/jtag/drivers/mchp_efp6.h b/src/jtag/drivers/mchp_efp6.h
new file mode 100644
index 0000000000..49b53a9520
--- /dev/null
+++ b/src/jtag/drivers/mchp_efp6.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef MCHP_EFP6
+#define MCHP_EFP6
+
+#include "mchp_fp.h"
+
+#define EFP6_VID       0x1514
+#define EFP6_REV_A_PID 0x200a
+#define EFP6_REV_B_PID 0x200b
+
+#define EFP6_MAX_SERIAL_STRING         126
+
+/* Discrete JTAG pins */
+#define EFP6_TRSTB_BIT                 0x4
+
+struct __attribute__((__packed__)) efp6_packet_atomic {
+       uint16_t packet_start;
+       uint16_t packet_type;
+       uint32_t address;
+       uint16_t len_high;
+       uint16_t len_low;
+       uint8_t data[2];
+       uint16_t crc;
+};
+
+struct efp6_ir_scan {
+       struct efp6_packet_atomic set_len;
+       struct efp6_packet_atomic data;
+       struct efp6_packet_atomic shift;
+       struct efp6_packet_atomic end_state;
+};
+
+#define EFP6_PACKET_OFFSET                     4
+#define EFP6_PACKET_HEADER_OPCODE_OFFSET       2
+#define EFP6_PACKET_HEADER_PREAMBLE_LENGTH     (10 + 
EFP6_PACKET_HEADER_OPCODE_OFFSET)
+#define EFP6_PACKET_HEADER_POSTAMBLE_LENGTH    2
+#define EFP6_PACKET_HEADER_TOTAL_LENGTH                
(EFP6_PACKET_HEADER_PREAMBLE_LENGTH + \
+                                                                               
                                                
EFP6_PACKET_HEADER_POSTAMBLE_LENGTH)
+
+#define EFP6_RESPONSE_PACKET_SIZE_ERROR                -100
+#define EFP6_RESPONSE_DEVICE_OPEN_ERROR                -101
+#define EFP6_RESPONSE_BITS_SIZE_ERROR          -102
+
+enum efp6_color {
+       EFP6_OFF,
+       EFP6_SOLID_GREEN,
+       EFP6_SOLID_RED,
+       EFP6_BLINK_GREEN = 5,
+       EFP6_BLINK_RED
+};
+
+static int mchp_efp6_get_cm3_version(void);
+static int mchp_efp6_enable_jtag_port(void);
+static int mchp_efp6_disable_jtag_port(void);
+static int mchp_efp6_set_led(uint8_t status);
+
+#endif
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index 64ebc48f03..72634c6286 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -404,5 +404,5 @@ extern struct adapter_driver vsllink_adapter_driver;
 extern struct adapter_driver xds110_adapter_driver;
 extern struct adapter_driver xlnx_pcie_xvc_adapter_driver;
 extern struct adapter_driver mchp_fp6_adapter_driver;
-
+extern struct adapter_driver mchp_efp6_adapter_driver;
 #endif /* OPENOCD_JTAG_INTERFACE_H */
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 1f376ec966..756a635efb 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -155,6 +155,9 @@ struct adapter_driver *adapter_drivers[] = {
 #endif
 #if BUILD_MICROCHIP_FP6 == 1
                &mchp_fp6_adapter_driver,
+#endif
+#if BUILD_MICROCHIP_EFP6 == 1
+               &mchp_efp6_adapter_driver,
 #endif
                NULL,
        };
diff --git a/tcl/board/microchip_riscv_efp6.cfg 
b/tcl/board/microchip_riscv_efp6.cfg
new file mode 100644
index 0000000000..ec5b14c40b
--- /dev/null
+++ b/tcl/board/microchip_riscv_efp6.cfg
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#**************************************************************************
+#   Copyright (C) 2015-2018 by Microchip Technology Inc.                  *
+#   http://www.microchip.com/support                                      *
+#                                                                         *
+#   This program is free software; you can redistribute it and/or modify  *
+#   it under the terms of the GNU General Public License as published by  *
+#   the Free Software Foundation; either version 2 of the License, or     *
+#   (at your option) any later version.                                   *
+#                                                                         *
+#   This program is distributed in the hope that it will be useful,       *
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+#   GNU General Public License for more details.                          *
+#                                                                         *
+#   You should have received a copy of the GNU General Public License     *
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+#**************************************************************************
+
+#------------------------------------------------------------------------------
+# Microchip RISC-V board
+#------------------------------------------------------------------------------
+
+# Device
+source [find interface/embedded_flashpro6.cfg]
+source [find target/microchip_riscv.cfg]
+
+# Board specific initialization
+proc do_board_reset_init {} {
+    # doesn't appear to be called
+}
+
diff --git a/tcl/interface/embedded_flashpro6.cfg 
b/tcl/interface/embedded_flashpro6.cfg
new file mode 100644
index 0000000000..26ad36585b
--- /dev/null
+++ b/tcl/interface/embedded_flashpro6.cfg
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+#
+# Embedded FlashPro6
+#
+adapter driver microchip-efp6
+
+# Specific Embedded FlashPro6
+# mchp_efp6 serial E7D1124E
+
+adapter speed 6000

-- 

Reply via email to