[[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
[[stlink], [ST-Link JTAG Programmer], [HLADAPTER_STLINK]],
[[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
- [[ulink], [Keil ULINK JTAG Programmer], [ULINK]]])
+ [[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
+ [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]]])
m4_define([USB_ADAPTERS],
[[[jlink], [Segger J-Link JTAG Programmer], [JLINK]],
AM_CONDITIONAL([USB_BLASTER_LIBFTDI], [test $build_usb_blaster_libftdi = yes])
AM_CONDITIONAL([USB_BLASTER_FTD2XX], [test $build_usb_blaster_ftd2xx = yes])
AM_CONDITIONAL([JTAG_VPI], [test $build_jtag_vpi = yes -o $build_jtag_vpi = yes])
-AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes])
+AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes -o $use_libusb1 = yes])
AM_CONDITIONAL([AMTJTAGACCEL], [test $build_amtjtagaccel = yes])
AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes])
AM_CONDITIONAL([PRESTO_LIBFTDI], [test $build_presto_libftdi = yes])
include $(top_srcdir)/common.mk
+AM_CPPFLAGS += -I$(top_srcdir)/src/jtag/drivers $(LIBUSB1_CFLAGS)
+
noinst_LTLIBRARIES = libocdusbblaster.la
libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC)
USB_BLASTER_SRC += ublast_access_ftd2xx.c
endif
+if USB_BLASTER_2
+USB_BLASTER_SRC += ublast2_access_libusb.c
+endif
+
noinst_HEADERS = ublast_access.h
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
--- /dev/null
+/*
+ * Driver for USB-JTAG, Altera USB-Blaster II and compatibles
+ *
+ * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <jtag/interface.h>
+#include <jtag/commands.h>
+#include <libusb_common.h>
+#include <target/image.h>
+
+#include "ublast_access.h"
+
+#define USBBLASTER_CTRL_READ_REV 0x94
+#define USBBLASTER_CTRL_LOAD_FIRM 0xA0
+#define USBBLASTER_EPOUT 4
+#define USBBLASTER_EPIN 8
+
+#define EZUSB_CPUCS 0xe600
+#define CPU_RESET 1
+
+/** Maximum size of a single firmware section. Entire EZ-USB code space = 16kB */
+#define SECTION_BUFFERSIZE 16384
+
+static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
+ unsigned size, uint32_t *bytes_read)
+{
+ *bytes_read = jtag_libusb_bulk_read(low->libusb_dev,
+ USBBLASTER_EPIN | \
+ LIBUSB_ENDPOINT_IN,
+ (char *)buf,
+ size,
+ 100);
+ return ERROR_OK;
+}
+
+static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf,
+ int size, uint32_t *bytes_written)
+{
+ *bytes_written = jtag_libusb_bulk_write(low->libusb_dev,
+ USBBLASTER_EPOUT | \
+ LIBUSB_ENDPOINT_OUT,
+ (char *)buf,
+ size,
+ 100);
+ return ERROR_OK;
+}
+
+static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libusb_dev,
+ struct image *firmware_image, int section_index)
+{
+ uint16_t chunk_size;
+ uint8_t data[SECTION_BUFFERSIZE];
+ uint8_t *data_ptr = data;
+ size_t size_read;
+
+ uint16_t size = (uint16_t)firmware_image->sections[section_index].size;
+ uint16_t addr = (uint16_t)firmware_image->sections[section_index].base_address;
+
+ LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr,
+ size);
+
+ if (data == NULL)
+ return ERROR_FAIL;
+
+ /* Copy section contents to local buffer */
+ int ret = image_read_section(firmware_image, section_index, 0, size, data,
+ &size_read);
+
+ if ((ret != ERROR_OK) || (size_read != size)) {
+ /* Propagating the return code would return '0' (misleadingly indicating
+ * successful execution of the function) if only the size check fails. */
+ return ERROR_FAIL;
+ }
+
+ uint16_t bytes_remaining = size;
+
+ /* Send section data in chunks of up to 64 bytes to ULINK */
+ while (bytes_remaining > 0) {
+ if (bytes_remaining > 64)
+ chunk_size = 64;
+ else
+ chunk_size = bytes_remaining;
+
+ jtag_libusb_control_transfer(libusb_dev,
+ LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_ENDPOINT_OUT,
+ USBBLASTER_CTRL_LOAD_FIRM,
+ addr,
+ 0,
+ (char *)data_ptr,
+ chunk_size,
+ 100);
+
+ bytes_remaining -= chunk_size;
+ addr += chunk_size;
+ data_ptr += chunk_size;
+ }
+
+ return ERROR_OK;
+}
+
+static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_dev,
+ struct ublast_lowlevel *low)
+{
+ struct image ublast2_firmware_image;
+
+ if (!low->firmware_path) {
+ LOG_ERROR("No firmware path specified");
+ return ERROR_FAIL;
+ }
+
+ ublast2_firmware_image.base_address = 0;
+ ublast2_firmware_image.base_address_set = 0;
+
+ int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex");
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Could not load firmware image");
+ return ret;
+ }
+
+ /** A host loader program must write 0x01 to the CPUCS register
+ * to put the CPU into RESET, load all or part of the EZUSB
+ * RAM with firmware, then reload the CPUCS register
+ * with ‘0’ to take the CPU out of RESET. The CPUCS register
+ * (at 0xE600) is the only EZ-USB register that can be written
+ * using the Firmware Download command.
+ */
+
+ char value = CPU_RESET;
+ jtag_libusb_control_transfer(libusb_dev,
+ LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_ENDPOINT_OUT,
+ USBBLASTER_CTRL_LOAD_FIRM,
+ EZUSB_CPUCS,
+ 0,
+ &value,
+ 1,
+ 100);
+
+ /* Download all sections in the image to ULINK */
+ for (int i = 0; i < ublast2_firmware_image.num_sections; i++) {
+ ret = ublast2_write_firmware_section(libusb_dev,
+ &ublast2_firmware_image, i);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Error while downloading the firmware");
+ return ret;
+ }
+ }
+
+ value = !CPU_RESET;
+ jtag_libusb_control_transfer(libusb_dev,
+ LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_ENDPOINT_OUT,
+ USBBLASTER_CTRL_LOAD_FIRM,
+ EZUSB_CPUCS,
+ 0,
+ &value,
+ 1,
+ 100);
+
+ image_close(&ublast2_firmware_image);
+
+ return ERROR_OK;
+}
+
+static int ublast2_libusb_init(struct ublast_lowlevel *low)
+{
+ const uint16_t vids[] = { low->ublast_vid_uninit, 0 };
+ const uint16_t pids[] = { low->ublast_pid_uninit, 0 };
+ struct jtag_libusb_device_handle *temp;
+ bool renumeration = false;
+ int ret;
+
+ if (jtag_libusb_open(vids, pids, &temp) == ERROR_OK) {
+ LOG_INFO("Altera USB-Blaster II (uninitialized) found");
+ LOG_INFO("Loading firmware...");
+ ret = load_usb_blaster_firmware(temp, low);
+ jtag_libusb_close(temp);
+ if (ret != ERROR_OK)
+ return ret;
+ renumeration = true;
+ }
+
+ const uint16_t vids_renum[] = { low->ublast_vid, 0 };
+ const uint16_t pids_renum[] = { low->ublast_pid, 0 };
+
+ if (renumeration == false) {
+ if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev) != ERROR_OK) {
+ LOG_ERROR("Altera USB-Blaster II not found");
+ return ERROR_FAIL;
+ }
+ } else {
+ int retry = 10;
+ while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev) != ERROR_OK && retry--) {
+ usleep(1000000);
+ LOG_INFO("Waiting for renumerate...");
+ }
+
+ if (!retry) {
+ LOG_ERROR("Altera USB-Blaster II not found");
+ return ERROR_FAIL;
+ }
+ }
+
+ char buffer[5];
+ jtag_libusb_control_transfer(low->libusb_dev,
+ LIBUSB_REQUEST_TYPE_VENDOR | \
+ LIBUSB_ENDPOINT_IN,
+ USBBLASTER_CTRL_READ_REV,
+ 0,
+ 0,
+ buffer,
+ 5,
+ 100);
+
+ LOG_INFO("Altera USB-Blaster II found (Firm. rev. = %s)", buffer);
+
+ return ERROR_OK;
+}
+
+static int ublast2_libusb_quit(struct ublast_lowlevel *low)
+{
+ jtag_libusb_close(low->libusb_dev);
+ return ERROR_OK;
+};
+
+static struct ublast_lowlevel low = {
+ .open = ublast2_libusb_init,
+ .close = ublast2_libusb_quit,
+ .read = ublast2_libusb_read,
+ .write = ublast2_libusb_write,
+ .flags = COPY_TDO_BUFFER,
+};
+
+struct ublast_lowlevel *ublast2_register_libusb(void)
+{
+ return &low;
+}
* Inspired from original code from Kolja Waschk's USB-JTAG project
* (http://www.ixo.de/info/usb_jtag/), and from openocd project.
*
+ * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com
* Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr
* Copyright (C) 2011 Ali Lown ali@lown.me.uk
* Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca
*
*/
+#include <libusb_common.h>
+
+/* Low level flags */
+#define COPY_TDO_BUFFER (1 << 0)
+
struct ublast_lowlevel {
uint16_t ublast_vid;
uint16_t ublast_pid;
+ uint16_t ublast_vid_uninit;
+ uint16_t ublast_pid_uninit;
char *ublast_device_desc;
+ struct jtag_libusb_device_handle *libusb_dev;
+ char *firmware_path;
int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size,
uint32_t *bytes_written);
int (*speed)(struct ublast_lowlevel *low, int speed);
void *priv;
+ int flags;
};
/**
* ublast_register_ftdi - get a lowlevel USB Blaster driver
* ublast_register_ftd2xx - get a lowlevel USB Blaster driver
+ * ublast2_register_libusb - get a lowlevel USB Blaster II driver
*
- * Get a lowlevel USB-Blaster driver. In the current implementation, there are 2
+ * Get a lowlevel USB-Blaster driver. In the current implementation, there are 3
* possible lowlevel drivers :
* - one based on libftdi from ftdichip.com
* - one based on libftdxx, the free alternative
+ * - one based on libusb, specific to the USB-Blaster II
*
* Returns the lowlevel driver structure.
*/
extern struct ublast_lowlevel *ublast_register_ftdi(void);
extern struct ublast_lowlevel *ublast_register_ftd2xx(void);
+extern struct ublast_lowlevel *ublast2_register_libusb(void);
* Inspired from original code from Kolja Waschk's USB-JTAG project
* (http://www.ixo.de/info/usb_jtag/), and from openocd project.
*
+ * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com
* Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr
* Copyright (C) 2011 Ali Lown ali@lown.me.uk
* Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca
* | 6 MHz XTAL | | 24 MHz Osc. |
* |_____________| |_____________|
*
+ * USB-JTAG, Altera USB-Blaster II are typically implemented as a Cypress
+ * EZ-USB FX2LP followed by a CPLD.
+ * _____________ _________
+ * | | | |
+ * USB__| EZ-USB FX2 |__| EPM570 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK)
+ * |_____________| |_________|
+ * __|__________
+ * | |
+ * | 24 MHz XTAL |
+ * |_____________|
*/
#ifdef HAVE_CONFIG_H
*/
#define BUF_LEN 4096
+/* USB-Blaster II specific command */
+#define CMD_COPY_TDO_BUFFER 0x5F
+
enum gpio_steer {
FIXED_0 = 0,
FIXED_1,
struct ublast_lowlevel *drv;
char *ublast_device_desc;
uint16_t ublast_vid, ublast_pid;
+ uint16_t ublast_vid_uninit, ublast_pid_uninit;
+ int flags;
+ char *firmware_path;
};
/*
#endif
#if BUILD_USB_BLASTER_FTD2XX
{ .name = "ftd2xx", .drv_register = ublast_register_ftd2xx },
+#endif
+#if BUILD_USB_BLASTER_2
+ { .name = "ublast2", .drv_register = ublast2_register_libusb },
#endif
{ NULL, NULL },
};
ublast_queue_bytes(&bits[i], trans);
else
ublast_queue_bytes(byte0, trans);
- if (read_tdos)
+ if (read_tdos) {
+ if (info.flags & COPY_TDO_BUFFER)
+ ublast_queue_byte(CMD_COPY_TDO_BUFFER);
ublast_read_byteshifted_tdos(&tdos[i], trans);
+ }
}
/*
else
ublast_clock_tdi(tdi, scan);
}
- if (nb1 && read_tdos)
+ if (nb1 && read_tdos) {
+ if (info.flags & COPY_TDO_BUFFER)
+ ublast_queue_byte(CMD_COPY_TDO_BUFFER);
ublast_read_bitbang_tdos(&tdos[nb8], nb1);
+ }
if (bits)
memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8));
LOG_ERROR("no lowlevel driver found");
return ERROR_JTAG_DEVICE_ERROR;
}
+ info.lowlevel_name = strdup(lowlevel_drivers_map[i-1].name);
}
/*
*/
info.drv->ublast_vid = info.ublast_vid;
info.drv->ublast_pid = info.ublast_pid;
+ info.drv->ublast_vid_uninit = info.ublast_vid_uninit;
+ info.drv->ublast_pid_uninit = info.ublast_pid_uninit;
info.drv->ublast_device_desc = info.ublast_device_desc;
+ info.drv->firmware_path = info.firmware_path;
+
+ info.flags |= info.drv->flags;
ret = info.drv->open(info.drv);
if (ret == ERROR_OK) {
COMMAND_HANDLER(ublast_handle_vid_pid_command)
{
- if (CMD_ARGC > 2) {
+ if (CMD_ARGC > 4) {
LOG_WARNING("ignoring extra IDs in ublast_vid_pid "
- "(maximum is 1 pair)");
- CMD_ARGC = 2;
+ "(maximum is 2 pairs)");
+ CMD_ARGC = 4;
}
- if (CMD_ARGC == 2) {
+
+ if (CMD_ARGC >= 2) {
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], info.ublast_vid);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], info.ublast_pid);
} else {
LOG_WARNING("incomplete ublast_vid_pid configuration");
}
+ if (CMD_ARGC == 4) {
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], info.ublast_vid_uninit);
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], info.ublast_pid_uninit);
+ } else {
+ LOG_WARNING("incomplete ublast_vid_pid configuration");
+ }
+
return ERROR_OK;
}
return ERROR_OK;
}
+COMMAND_HANDLER(ublast_firmware_command)
+{
+ if (CMD_ARGC == 1)
+ info.firmware_path = strdup(CMD_ARGV[0]);
+ else
+ LOG_ERROR("require exactly one argument to "
+ "ublast_firmware_command <path>");
+
+ return ERROR_OK;
+}
+
+
static const struct command_registration ublast_command_handlers[] = {
{
.name = "usb_blaster_device_desc",
.name = "usb_blaster_vid_pid",
.handler = ublast_handle_vid_pid_command,
.mode = COMMAND_CONFIG,
- .help = "the vendor ID and product ID of the USB-Blaster",
- .usage = "vid pid",
+ .help = "the vendor ID and product ID of the USB-Blaster and " \
+ "vendor ID and product ID of the uninitialized device " \
+ "for USB-Blaster II",
+ .usage = "vid pid vid_uninit pid_uninit",
},
{
.name = "usb_blaster_lowlevel_driver",
.handler = ublast_handle_lowlevel_drv_command,
.mode = COMMAND_CONFIG,
- .help = "set the lowlevel access for the USB Blaster (ftdi, ftd2xx)",
- .usage = "(ftdi|ftd2xx)",
+ .help = "set the lowlevel access for the USB Blaster (ftdi, ftd2xx, ublast2)",
+ .usage = "(ftdi|ftd2xx|ublast2)",
},
{
.name = "usb_blaster_pin",
.mode = COMMAND_ANY,
.help = "show or set pin state for the unused GPIO pins",
.usage = "(pin6|pin8) (0|1|s|t)",
+ },
+ {
+ .name = "usb_blaster_firmware",
+ .handler = &ublast_firmware_command,
+ .mode = COMMAND_CONFIG,
+ .help = "configure the USB-Blaster II firmware location",
+ .usage = "path/to/blaster_xxxx.hex",
},
COMMAND_REGISTRATION_DONE
};
#if BUILD_FTDI == 1
extern struct jtag_interface ftdi_interface;
#endif
-#if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1
+#if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1 || BUILD_USB_BLASTER_2 == 1
extern struct jtag_interface usb_blaster_interface;
#endif
#if BUILD_JTAG_VPI == 1
#if BUILD_FTDI == 1
&ftdi_interface,
#endif
-#if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1
+#if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1 || BUILD_USB_BLASTER_2 == 1
&usb_blaster_interface,
#endif
#if BUILD_JTAG_VPI == 1
--- /dev/null
+#
+# Altera USB-Blaster II
+#
+
+interface usb_blaster
+usb_blaster_vid_pid 0x09fb 0x6010 0x09fb 0x6810
+usb_blaster_lowlevel_driver ublast2
+usb_blaster_firmware /path/to/quartus/blaster_6810.hex