]> git.sur5r.net Git - openocd/blobdiff - src/jtag/drivers/vsllink.c
configure the SWD frequency when setting adapter speed in SWD mode for versaloon
[openocd] / src / jtag / drivers / vsllink.c
index 250b495d179fc9c182743a23244d0b63d3e2e401..f82dff911666ad87a8f33222759705182a47b31c 100644 (file)
@@ -28,7 +28,8 @@
 
 #include <jtag/interface.h>
 #include <jtag/commands.h>
-#include "usb_common.h"
+#include <jtag/swd.h>
+#include <libusb.h>
 
 #include "versaloon/versaloon_include.h"
 #include "versaloon/versaloon.h"
@@ -70,12 +71,19 @@ static void vsllink_tap_ensure_pending(int scans);
 static void vsllink_tap_append_scan(int length, uint8_t *buffer,
                struct scan_command *command);
 
+/* VSLLink SWD functions */
+static int_least32_t vsllink_swd_frequency(struct adiv5_dap *dap,
+               int_least32_t hz);
+static int vsllink_swd_switch_seq(struct adiv5_dap *dap,
+               enum swd_special_seq seq);
+
 /* VSLLink lowlevel functions */
 struct vsllink {
-       struct usb_dev_handle *usb_handle;
+       struct libusb_context *libusb_ctx;
+       struct libusb_device_handle *usb_device_handle;
 };
 
-static struct vsllink *vsllink_usb_open(void);
+static int vsllink_usb_open(struct vsllink *vsllink);
 static void vsllink_usb_close(struct vsllink *vsllink);
 
 #if defined _DEBUG_JTAG_IO_
@@ -88,7 +96,9 @@ static uint8_t *tms_buffer;
 static uint8_t *tdi_buffer;
 static uint8_t *tdo_buffer;
 
-struct vsllink *vsllink_handle;
+static bool swd_mode;
+
+static struct vsllink *vsllink_handle;
 
 static int vsllink_execute_queue(void)
 {
@@ -232,6 +242,11 @@ static int vsllink_execute_queue(void)
 
 static int vsllink_speed(int speed)
 {
+       if (swd_mode) {
+               vsllink_swd_frequency(NULL, speed * 1000);
+               return ERROR_OK;
+       }
+
        versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed);
        return versaloon_interface.adaptors.peripheral_commit();
 }
@@ -271,20 +286,34 @@ static int vsllink_quit(void)
        versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
                0, 0, GPIO_SRST | GPIO_TRST);
        versaloon_interface.adaptors.gpio.fini(0);
-       versaloon_interface.adaptors.jtag_raw.fini(0);
+
+       if (swd_mode)
+               versaloon_interface.adaptors.swd.fini(0);
+       else
+               versaloon_interface.adaptors.jtag_raw.fini(0);
+
        versaloon_interface.adaptors.peripheral_commit();
        versaloon_interface.fini();
 
        vsllink_free_buffer();
        vsllink_usb_close(vsllink_handle);
 
+       free(vsllink_handle);
+
        return ERROR_OK;
 }
 
-static int vsllink_init(void)
+static int vsllink_interface_init(void)
 {
-       vsllink_handle = vsllink_usb_open();
-       if (vsllink_handle == 0) {
+       vsllink_handle = malloc(sizeof(struct vsllink));
+       if (NULL == vsllink_handle) {
+               LOG_ERROR("unable to allocate memory");
+               return ERROR_FAIL;
+       }
+
+       libusb_init(&vsllink_handle->libusb_ctx);
+
+       if (ERROR_OK != vsllink_usb_open(vsllink_handle)) {
                LOG_ERROR("Can't find USB JTAG Interface!" \
                        "Please check connection and permissions.");
                return ERROR_JTAG_INIT_FAILED;
@@ -292,7 +321,7 @@ static int vsllink_init(void)
        LOG_DEBUG("vsllink found on %04X:%04X",
                versaloon_interface.usb_setting.vid,
                versaloon_interface.usb_setting.pid);
-       versaloon_usb_device_handle = vsllink_handle->usb_handle;
+       versaloon_usb_device_handle = vsllink_handle->usb_device_handle;
 
        if (ERROR_OK != versaloon_interface.init())
                return ERROR_FAIL;
@@ -301,22 +330,46 @@ static int vsllink_init(void)
                return ERROR_FAIL;
        }
 
-       /* malloc buffer size for tap */
-       tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32;
-       vsllink_free_buffer();
-       tdi_buffer = malloc(tap_buffer_size);
-       tdo_buffer = malloc(tap_buffer_size);
-       tms_buffer = malloc(tap_buffer_size);
-       if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) {
-               vsllink_quit();
-               return ERROR_FAIL;
-       }
+       return ERROR_OK;
+}
+
+static int vsllink_init(void)
+{
+       int retval = vsllink_interface_init();
+       if (ERROR_OK != retval)
+               return retval;
 
-       versaloon_interface.adaptors.jtag_raw.init(0);
-       versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz());
        versaloon_interface.adaptors.gpio.init(0);
-       versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
-               GPIO_TRST, GPIO_SRST, GPIO_SRST);
+       versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, 0, GPIO_SRST,
+               GPIO_SRST);
+       versaloon_interface.adaptors.delay.delayms(100);
+       versaloon_interface.adaptors.peripheral_commit();
+
+       if (swd_mode) {
+               versaloon_interface.adaptors.gpio.config(0, GPIO_TRST, 0,
+                       GPIO_TRST, GPIO_TRST);
+               versaloon_interface.adaptors.swd.init(0);
+               vsllink_swd_frequency(NULL, jtag_get_speed_khz() * 1000);
+               vsllink_swd_switch_seq(NULL, JTAG_TO_SWD);
+
+       } else {
+               /* malloc buffer size for tap */
+               tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32;
+               vsllink_free_buffer();
+               tdi_buffer = malloc(tap_buffer_size);
+               tdo_buffer = malloc(tap_buffer_size);
+               tms_buffer = malloc(tap_buffer_size);
+               if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) {
+                       vsllink_quit();
+                       return ERROR_FAIL;
+               }
+
+               versaloon_interface.adaptors.jtag_raw.init(0);
+               versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz());
+               versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
+                       GPIO_TRST, GPIO_SRST, GPIO_SRST);
+       }
+
        if (ERROR_OK != versaloon_interface.adaptors.peripheral_commit())
                return ERROR_FAIL;
 
@@ -442,10 +495,13 @@ static void vsllink_reset(int trst, int srst)
        else
                versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, GPIO_SRST, 0, 0);
 
-       if (!trst)
-               versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST);
-       else
-               versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0);
+       if (!swd_mode) {
+               if (!trst)
+                       versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST);
+               else
+                       versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0);
+       }
+
        versaloon_interface.adaptors.peripheral_commit();
 }
 
@@ -468,6 +524,21 @@ COMMAND_HANDLER(vsllink_handle_usb_pid_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(vsllink_handle_usb_serial_command)
+{
+       if (CMD_ARGC > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       free(versaloon_interface.usb_setting.serialstring);
+
+       if (CMD_ARGC == 1)
+               versaloon_interface.usb_setting.serialstring = strdup(CMD_ARGV[0]);
+       else
+               versaloon_interface.usb_setting.serialstring = NULL;
+
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(vsllink_handle_usb_bulkin_command)
 {
        if (CMD_ARGC != 1)
@@ -645,141 +716,189 @@ static int vsllink_jtag_execute(void)
 
 static int vsllink_tap_execute(void)
 {
+       if (swd_mode)
+               return ERROR_OK;
+
        return vsllink_jtag_execute();
 }
 
-/****************************************************************************
- * VSLLink USB low-level functions */
+static int vsllink_swd_init(void)
+{
+       LOG_INFO("VSLLink SWD mode enabled");
+       swd_mode = true;
 
-static uint8_t usb_check_string(usb_dev_handle *usb, uint8_t stringidx,
-       char *string, char *buff, uint16_t buf_size)
+       return ERROR_OK;
+}
+
+static int_least32_t vsllink_swd_frequency(struct adiv5_dap *dap,
+               int_least32_t hz)
 {
-       int len;
-       uint8_t alloced = 0;
-       uint8_t ret = 1;
+       const int_least32_t delay2hz[] = {
+               1850000, 235000, 130000, 102000, 85000, 72000
+       };
+
+       if (hz > 0) {
+               uint16_t delay = UINT16_MAX;
 
-       if (NULL == buff) {
-               buf_size = 256;
-               buff = malloc(buf_size);
-               if (NULL == buff) {
-                       ret = 0;
-                       goto free_and_return;
+               for (uint16_t i = 0; i < ARRAY_SIZE(delay2hz); i++) {
+                       if (hz >= delay2hz[i]) {
+                               hz = delay2hz[i];
+                               delay = i;
+                               break;
+                       }
                }
-               alloced = 1;
-       }
 
-       strcpy(buff, "");
-       len = usb_get_string_simple(usb, stringidx, buff, buf_size);
-       if ((len < 0) || ((size_t)len != strlen(buff))) {
-               ret = 0;
-               goto free_and_return;
-       }
+               if (delay == UINT16_MAX)
+                       delay = (500000 / hz) - 1;
+
+               /* Calculate retry count after a WAIT response. This will give
+                * a retry timeout at about ~250 ms. 54 is the number of bits
+                * found in a transaction. */
+               uint16_t retry_count = 250 * hz / 1000 / 54;
 
-       buff[len] = '\0';
-       if ((string != NULL) && strcmp(buff, string)) {
-               ret = 0;
-               goto free_and_return;
+               LOG_DEBUG("SWD delay: %d, retry count: %d", delay, retry_count);
+
+               versaloon_interface.adaptors.swd.config(0, 2, retry_count, delay);
        }
 
-free_and_return:
-       if (alloced && (buff != NULL)) {
-               free(buff);
-               buff = NULL;
+       return hz;
+}
+
+static int vsllink_swd_switch_seq(struct adiv5_dap *dap,
+               enum swd_special_seq seq)
+{
+       switch (seq) {
+       case LINE_RESET:
+               LOG_DEBUG("SWD line reset");
+               versaloon_interface.adaptors.swd.seqout(0, swd_seq_line_reset,
+                               swd_seq_line_reset_len);
+               break;
+       case JTAG_TO_SWD:
+               LOG_DEBUG("JTAG-to-SWD");
+               versaloon_interface.adaptors.swd.seqout(0, swd_seq_jtag_to_swd,
+                               swd_seq_jtag_to_swd_len);
+               break;
+       case SWD_TO_JTAG:
+               LOG_DEBUG("SWD-to-JTAG");
+               versaloon_interface.adaptors.swd.seqout(0, swd_seq_swd_to_jtag,
+                               swd_seq_swd_to_jtag_len);
+               break;
+       default:
+               LOG_ERROR("Sequence %d not supported", seq);
+               return ERROR_FAIL;
        }
-       return ret;
-}
-
-static usb_dev_handle *find_usb_device(uint16_t VID, uint16_t PID,
-       uint8_t interface, int8_t serialindex, char *serialstring,
-       int8_t productindex, char *productstring)
-{
-       usb_dev_handle *dev_handle = NULL;
-       struct usb_bus *busses;
-       struct usb_bus *bus;
-       struct usb_device *dev;
-
-       usb_init();
-       usb_find_busses();
-       usb_find_devices();
-       busses = usb_get_busses();
-
-       for (bus = busses; bus; bus = bus->next) {
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       if ((dev->descriptor.idVendor == VID)
-                           && (dev->descriptor.idProduct == PID)) {
-                               dev_handle = usb_open(dev);
-                               if (NULL == dev_handle) {
-                                       LOG_ERROR("failed to open %04X:%04X, %s", VID, PID,
-                                               usb_strerror());
-                                       continue;
-                               }
 
-                               /* check description string */
-                               if (((productstring != NULL) && (productindex >= 0)
-                                               && !usb_check_string(dev_handle, productindex,
-                                               productstring, NULL, 0))
-                                               || ((serialstring != NULL) && (serialindex >= 0)
-                                       && !usb_check_string(dev_handle, serialindex,
-                                               serialstring, NULL, 0))) {
-                                       usb_close(dev_handle);
-                                       dev_handle = NULL;
-                                       continue;
-                               }
+       return ERROR_OK;
+}
 
-                               if (usb_claim_interface(dev_handle, interface) != 0) {
-                                       LOG_ERROR(ERRMSG_FAILURE_OPERATION_MESSAGE,
-                                               "claim interface", usb_strerror());
-                                       usb_close(dev_handle);
-                                       dev_handle = NULL;
-                                       continue;
-                               }
+static void vsllink_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd,
+               uint32_t *value)
+{
+       versaloon_interface.adaptors.swd.transact(0, cmd, value, NULL);
+}
 
-                               if (dev_handle != NULL)
-                                       return dev_handle;
-                       }
-               }
-       }
+static void vsllink_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd,
+               uint32_t value)
+{
+       versaloon_interface.adaptors.swd.transact(0, cmd, &value, NULL);
+}
 
-       return dev_handle;
+static int vsllink_swd_run_queue(struct adiv5_dap *dap)
+{
+       return versaloon_interface.adaptors.peripheral_commit();
 }
 
-static struct vsllink *vsllink_usb_open(void)
+/****************************************************************************
+ * VSLLink USB low-level functions */
+
+static int vsllink_check_usb_strings(
+       struct libusb_device_handle *usb_device_handle,
+       struct libusb_device_descriptor *usb_desc)
 {
-       usb_init();
+       char desc_string[256];
+       int retval;
+
+       if (NULL != versaloon_interface.usb_setting.serialstring) {
+               retval = libusb_get_string_descriptor_ascii(usb_device_handle,
+                       usb_desc->iSerialNumber, (unsigned char *)desc_string,
+                       sizeof(desc_string));
+               if (retval < 0)
+                       return ERROR_FAIL;
+
+               if (strncmp(desc_string, versaloon_interface.usb_setting.serialstring,
+                               sizeof(desc_string)))
+                       return ERROR_FAIL;
+       }
 
-       struct usb_dev_handle *dev;
+       retval = libusb_get_string_descriptor_ascii(usb_device_handle,
+               usb_desc->iProduct, (unsigned char *)desc_string,
+               sizeof(desc_string));
+       if (retval < 0)
+               return ERROR_FAIL;
 
-       dev = find_usb_device(versaloon_interface.usb_setting.vid,
-                       versaloon_interface.usb_setting.pid,
-                       versaloon_interface.usb_setting.interface,
-                       0, NULL, 2, "Versaloon");
-       if (NULL == dev)
-               return NULL;
+       if (strstr(desc_string, "Versaloon") == NULL)
+               return ERROR_FAIL;
 
-       struct vsllink *result = malloc(sizeof(struct vsllink));
-       result->usb_handle = dev;
-       return result;
+       return ERROR_OK;
 }
 
-static void vsllink_usb_close(struct vsllink *vsllink)
+static int vsllink_usb_open(struct vsllink *vsllink)
 {
-       int ret;
+       ssize_t num_devices, i;
+       libusb_device **usb_devices;
+       struct libusb_device_descriptor usb_desc;
+       struct libusb_device_handle *usb_device_handle;
+       int retval;
 
-       ret = usb_release_interface(vsllink->usb_handle,
-                       versaloon_interface.usb_setting.interface);
-       if (ret != 0) {
-               LOG_ERROR("fail to release interface %d, %d returned",
-                       versaloon_interface.usb_setting.interface, ret);
-               exit(-1);
+       num_devices = libusb_get_device_list(vsllink->libusb_ctx, &usb_devices);
+
+       if (num_devices <= 0)
+               return ERROR_FAIL;
+
+       for (i = 0; i < num_devices; i++) {
+               libusb_device *device = usb_devices[i];
+
+               retval = libusb_get_device_descriptor(device, &usb_desc);
+               if (retval != 0)
+                       continue;
+
+               if (usb_desc.idVendor != versaloon_interface.usb_setting.vid ||
+                       usb_desc.idProduct != versaloon_interface.usb_setting.pid)
+                       continue;
+
+               retval = libusb_open(device, &usb_device_handle);
+               if (retval != 0)
+                       continue;
+
+               retval = vsllink_check_usb_strings(usb_device_handle, &usb_desc);
+               if (ERROR_OK == retval)
+                       break;
+
+               libusb_close(usb_device_handle);
        }
 
-       ret = usb_close(vsllink->usb_handle);
-       if (ret != 0) {
-               LOG_ERROR("fail to close usb, %d returned", ret);
-               exit(-1);
+       libusb_free_device_list(usb_devices, 1);
+
+       if (i == num_devices)
+               return ERROR_FAIL;
+
+       retval = libusb_claim_interface(usb_device_handle,
+               versaloon_interface.usb_setting.interface);
+       if (retval != 0) {
+               LOG_ERROR("unable to claim interface");
+               libusb_close(usb_device_handle);
+               return ERROR_FAIL;
        }
 
-       free(vsllink);
+       vsllink->usb_device_handle = usb_device_handle;
+       return ERROR_OK;
+}
+
+static void vsllink_usb_close(struct vsllink *vsllink)
+{
+       libusb_release_interface(vsllink->usb_device_handle,
+               versaloon_interface.usb_setting.interface);
+       libusb_close(vsllink->usb_device_handle);
 }
 
 #define BYTES_PER_LINE  16
@@ -814,6 +933,11 @@ static const struct command_registration vsllink_command_handlers[] = {
                .handler = &vsllink_handle_usb_pid_command,
                .mode = COMMAND_CONFIG,
        },
+       {
+               .name = "vsllink_usb_serial",
+               .handler = &vsllink_handle_usb_serial_command,
+               .mode = COMMAND_CONFIG,
+       },
        {
                .name = "vsllink_usb_bulkin",
                .handler = &vsllink_handle_usb_bulkin_command,
@@ -832,13 +956,23 @@ static const struct command_registration vsllink_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
-static const char *vsllink_transports[] = {"jtag", "swd", NULL};
+static const char * const vsllink_transports[] = {"jtag", "swd", NULL};
+
+static const struct swd_driver vsllink_swd_driver = {
+       .init = vsllink_swd_init,
+       .frequency = vsllink_swd_frequency,
+       .switch_seq = vsllink_swd_switch_seq,
+       .read_reg = vsllink_swd_read_reg,
+       .write_reg = vsllink_swd_write_reg,
+       .run = vsllink_swd_run_queue,
+};
 
 struct jtag_interface vsllink_interface = {
        .name = "vsllink",
        .supported = DEBUG_CAP_TMS_SEQ,
        .commands = vsllink_command_handlers,
        .transports = vsllink_transports,
+       .swd = &vsllink_swd_driver,
 
        .init = vsllink_init,
        .quit = vsllink_quit,