diff --git a/configure.ac b/configure.ac index 68546db25..73f7bef67 100644 --- a/configure.ac +++ b/configure.ac @@ -195,7 +195,8 @@ m4_define([USB1_ADAPTERS], [[[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]], @@ -1161,7 +1162,7 @@ AM_CONDITIONAL([FT2232_DRIVER], [test $build_ft2232_ftd2xx = yes -o $build_ft223 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]) diff --git a/src/jtag/drivers/usb_blaster/Makefile.am b/src/jtag/drivers/usb_blaster/Makefile.am index 1cf7ba996..95e84fecd 100644 --- a/src/jtag/drivers/usb_blaster/Makefile.am +++ b/src/jtag/drivers/usb_blaster/Makefile.am @@ -1,5 +1,7 @@ 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) @@ -13,6 +15,10 @@ if USB_BLASTER_FTD2XX 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 diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c new file mode 100644 index 000000000..437150d75 --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -0,0 +1,253 @@ +/* + * 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 +#endif +#include +#include +#include +#include + +#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; +} diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h index e0eb059e2..9a9762c8d 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access.h +++ b/src/jtag/drivers/usb_blaster/ublast_access.h @@ -4,6 +4,7 @@ * 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 @@ -21,10 +22,19 @@ * */ +#include + +/* 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); @@ -35,18 +45,22 @@ struct ublast_lowlevel { 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); diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 00a2cd084..1a43f588f 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -4,6 +4,7 @@ * 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 @@ -48,6 +49,16 @@ * | 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 @@ -82,6 +93,9 @@ */ #define BUF_LEN 4096 +/* USB-Blaster II specific command */ +#define CMD_COPY_TDO_BUFFER 0x5F + enum gpio_steer { FIXED_0 = 0, FIXED_1, @@ -103,6 +117,9 @@ struct ublast_info { 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; }; /* @@ -132,6 +149,9 @@ static struct drvs_map lowlevel_drivers_map[] = { #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 }, }; @@ -631,8 +651,11 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) 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); + } } /* @@ -645,8 +668,11 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) 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)); @@ -804,6 +830,7 @@ static int ublast_init(void) LOG_ERROR("no lowlevel driver found"); return ERROR_JTAG_DEVICE_ERROR; } + info.lowlevel_name = strdup(lowlevel_drivers_map[i-1].name); } /* @@ -811,7 +838,12 @@ static int ublast_init(void) */ 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) { @@ -860,18 +892,26 @@ COMMAND_HANDLER(ublast_handle_device_desc_command) 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; } @@ -951,6 +991,18 @@ COMMAND_HANDLER(ublast_handle_lowlevel_drv_command) 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 "); + + return ERROR_OK; +} + + static const struct command_registration ublast_command_handlers[] = { { .name = "usb_blaster_device_desc", @@ -963,15 +1015,17 @@ static const struct command_registration ublast_command_handlers[] = { .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", @@ -979,6 +1033,13 @@ static const struct command_registration ublast_command_handlers[] = { .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 }; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index d0bc3827e..62c5d4598 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -62,7 +62,7 @@ extern struct jtag_interface ft2232_interface; #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 @@ -161,7 +161,7 @@ struct jtag_interface *jtag_interfaces[] = { #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 diff --git a/tcl/interface/altera-usb-blaster2.cfg b/tcl/interface/altera-usb-blaster2.cfg new file mode 100644 index 000000000..c35be1970 --- /dev/null +++ b/tcl/interface/altera-usb-blaster2.cfg @@ -0,0 +1,8 @@ +# +# 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