Adds support for the Altera USB-Blaster programming dongle in SPI mode. Tested on both original product and a clone dongle.
Signed-off-by: James Laird jhl@mafipulation.org [km: Handle issues from review, cleanup and rebase.] Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com
diff --git a/Makefile b/Makefile index 9309ce5..e88fbd3 100644 --- a/Makefile +++ b/Makefile @@ -105,7 +105,7 @@ UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes else override CONFIG_PONY_SPI = no endif -# Dediprog and FT2232 are not supported under DOS (missing USB support). +# Dediprog, FT2232 and USB-Blaster are not supported under DOS (missing USB support). ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -116,6 +116,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no +endif endif
# FIXME: Should we check for Cygwin/MSVC as well? @@ -217,7 +222,7 @@ UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes else override CONFIG_SERPROG = no endif -# Dediprog and FT2232 are not supported with libpayload (missing libusb support) +# Dediprog, FT2232 and USB-Blaster are not supported with libpayload (missing libusb support) ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -228,6 +233,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no +endif endif
ifneq ($(TARGET_OS), Linux) @@ -370,6 +380,9 @@ CONFIG_SATAMV ?= yes # Enable Linux spidev interface by default. We disable it on non-Linux targets. CONFIG_LINUX_SPI ?= yes
+# Always enable USB-Blaster SPI for now. +CONFIG_USBBLASTER_SPI ?= yes + # Disable wiki printing by default. It is only useful if you have wiki access. CONFIG_PRINT_WIKI ?= no
@@ -459,12 +472,29 @@ PROGRAMMER_OBJS += atahpt.o NEED_PCI := yes endif
-ifeq ($(CONFIG_FT2232_SPI), yes) -FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") # This is a totally ugly hack. -FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'") -FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -PROGRAMMER_OBJS += ft2232_spi.o +WANT_LIBFTDI := no +HAVE_LIBFTDI := $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && echo "yes") +ifeq ($(CONFIG_FT2232_SPI), yes) + WANT_LIBFTDI := yes + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += -DCONFIG_FT2232_SPI=1 + PROGRAMMER_OBJS += ft2232_spi.o + endif +endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) + WANT_LIBFTDI := yes + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += -DCONFIG_USBBLASTER_SPI=1 + PROGRAMMER_OBJS += usbblaster_spi.o + endif +endif + +ifeq ($(WANT_LIBFTDI), yes) + ifeq ($(HAVE_LIBFTDI), yes) + FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") + FEATURE_LIBS += $(FTDILIBS) + endif endif
ifeq ($(CONFIG_DUMMY), yes) @@ -745,7 +775,7 @@ export LINUX_SPI_TEST
features: compiler @echo "FEATURES := yes" > .features.tmp -ifeq ($(CONFIG_FT2232_SPI), yes) +ifeq ($(WANT_LIBFTDI), yes) @printf "Checking for FTDI support... " @echo "$$FTDI_TEST" > .featuretest.c @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ diff --git a/README b/README index 8e812be..7f24cca 100644 --- a/README +++ b/README @@ -45,8 +45,8 @@ Build Instructions To build flashrom you need to install the following software:
* pciutils+libpci (if you want support for mainboard or PCI device flashing) - * libusb (if you want FT2232 or Dediprog support) - * libftdi (if you want FT2232 support) + * libusb (if you want FT2232, Dediprog or USB-Blaster support) + * libftdi (if you want FT2232 or USB-Blaster support)
Linux et al:
diff --git a/flashrom.c b/flashrom.c index fdc5412..0bd3a4a 100644 --- a/flashrom.c +++ b/flashrom.c @@ -262,6 +262,16 @@ const struct programmer_entry programmer_table[] = { }, #endif
+#if CONFIG_USBBLASTER_SPI == 1 + { + .name = "usbblaster_spi", + .init = usbblaster_spi_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + {0}, /* This entry corresponds to PROGRAMMER_INVALID. */ };
diff --git a/print.c b/print.c index 582a49e..e23e9e6 100644 --- a/print.c +++ b/print.c @@ -547,6 +547,11 @@ void print_supported(void) programmer_table[PROGRAMMER_LINUX_SPI].name); msg_ginfo("Device files /dev/spidev*.*\n"); #endif +#if CONFIG_USBBLASTER_SPI == 1 + msg_ginfo("\nSupported devices for the %s programmer:\n", + programmer_table[PROGRAMMER_USBBLASTER_SPI].name); + msg_ginfo("Altera USB-Blaster cable\n"); +#endif }
#if CONFIG_INTERNAL == 1 diff --git a/programmer.h b/programmer.h index 51b9c40..2c2063c 100644 --- a/programmer.h +++ b/programmer.h @@ -87,6 +87,9 @@ enum programmer { #if CONFIG_LINUX_SPI == 1 PROGRAMMER_LINUX_SPI, #endif +#if CONFIG_USBBLASTER_SPI == 1 + PROGRAMMER_USBBLASTER_SPI, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ };
@@ -434,6 +437,11 @@ extern const struct usbdev_status devs_ft2232spi[]; void print_supported_usbdevs(const struct usbdev_status *devs); #endif
+/* usbblaster_spi.c */ +#if CONFIG_USBBLASTER_SPI == 1 +int usbblaster_spi_init(void); +#endif + /* rayer_spi.c */ #if CONFIG_RAYER_SPI == 1 int rayer_spi_init(void); @@ -512,6 +520,9 @@ enum spi_controller { #if CONFIG_SERPROG == 1 SPI_CONTROLLER_SERPROG, #endif +#if CONFIG_USBBLASTER_SPI == 1 + SPI_CONTROLLER_USBBLASTER, +#endif };
#define MAX_DATA_UNSPECIFIED 0 diff --git a/usbblaster_spi.c b/usbblaster_spi.c new file mode 100644 index 0000000..01fc722 --- /dev/null +++ b/usbblaster_spi.c @@ -0,0 +1,227 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2012 James Laird jhl@mafipulation.org + * + * 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; version 2 of the License. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Device should be connected as per "active serial" mode: + * + * +---------+------+-----------+ + * | SPI | Pin | Altera | + * +---------+------+-----------+ + * | SCLK | 1 | DCLK | + * | GND | 2,10 | GND | + * | VCC | 4 | VCC(TRGT) | + * | MISO | 7 | ASDO | + * | /CS | 8 | nCS | + * | MOSI | 9 | ASDI | + * +---------+------+-----------+ + */ + +#if CONFIG_USBBLASTER_SPI == 1 + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "flash.h" +#include "programmer.h" +#include "spi.h" +#include <ftdi.h> + +/* Please keep sorted by vendor ID, then device ID. */ + +#define ALTERA_VID 0x09fb +#define ALTERA_USBBLASTER_PID 0x6001 + +const struct usbdev_status devs_usbblasterspi[] = { + {ALTERA_VID, ALTERA_USBBLASTER_PID, NT, "Altera", "USB-Blaster"}, + {}, +}; + +static const struct spi_programmer spi_programmer_usbblaster; + +static struct ftdi_context ftdic; + +// command bytes +#define BIT_BYTE (1<<7) // byte mode (rather than bitbang) +#define BIT_READ (1<<6) // read request + +#define BIT_LED (1<<5) +#define BIT_CS (1<<3) +#define BIT_CLK (1<<0) +#define BIT_TMS (1<<1) + +// The programmer shifts bits in the wrong order for SPI. +uint8_t reverse(uint8_t b) +{ + b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; + return b; +} + + +/* Returns 0 upon success, a negative number upon errors. */ +int usbblaster_spi_init(void) +{ + if (ftdi_init(&ftdic) < 0) + return -1; + + if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) { + msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str); + return -1; + } + + if (ftdi_usb_reset(&ftdic) < 0) { + msg_perr("Blaster reset failed\n"); + return -1; + } + + if (ftdi_set_latency_timer(&ftdic, 2) < 0) { + msg_perr("Blaster set latency timer failed\n"); + return -1; + } + + if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 || + ftdi_read_data_set_chunksize(&ftdic, 64) < 0) { + msg_perr("Blaster set chunk size failed\n"); + return -1; + } + uint8_t buf[65]; + memset(buf, 0, sizeof(buf)); + buf[sizeof(buf)-1] = BIT_LED | BIT_CS; + if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("Blaster reset write failed\n"); + return -1; + } + if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("Blaster reset read failed\n"); + return -1; + } + + register_spi_programmer(&spi_programmer_usbblaster); + return 0; +} + +static int send_write(unsigned int writecnt, const unsigned char *writearr) +{ + uint8_t buf[64]; + int i; + + memset(buf, 0, sizeof(buf)); + while (writecnt) { + unsigned int n_write = writecnt; + if (n_write > 63) + n_write = 63; + + msg_pspew("writing %d-byte packet\n", n_write); + + buf[0] = BIT_BYTE | (uint8_t)n_write; + for (i=0; i<n_write; i++) { + buf[i+1] = reverse(writearr[i]); + } + if (ftdi_write_data(&ftdic, buf, n_write+1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + writearr += n_write; + writecnt -= n_write; + } + return 0; +} + +static int send_read(unsigned int readcnt, unsigned char *readarr) +{ + uint8_t buf[64]; + int i; + + memset(buf, 0, sizeof(buf)); + unsigned int n_readout = readcnt; + while (readcnt) { + unsigned int n_read = readcnt; + if (n_read > 63) + n_read = 63; + + buf[0] = BIT_BYTE | BIT_READ | (uint8_t)n_read; + if (ftdi_write_data(&ftdic, buf, n_read + 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + readcnt -= n_read; + msg_pspew("reading %d-byte packet\n", n_read); + }; + + unsigned int n_read = n_readout; + while (n_read) { + int ret = ftdi_read_data(&ftdic, readarr, n_read); + if (ret < 0) { + msg_perr("Blaster read failed\n"); + return -1; + } + for (i=0; i<ret; i++) { + readarr[i] = reverse(readarr[i]); + } + n_read -= ret; + readarr += ret; + } + return 0; +} + +/* Returns 0 upon success, a negative number upon errors. */ +static int usbblaster_spi_send_command(struct flashctx *flash, + unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + int ret = 0; + uint8_t cmd; + // assert /CS + cmd = BIT_LED; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + ret = -1; + } + + if (!ret && writecnt) + ret = send_write(writecnt, writearr); + + if (!ret && readcnt) + ret = send_read(readcnt, readarr); + + cmd = BIT_CS; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + ret = -1; + } + + return ret; +} + + +static const struct spi_programmer spi_programmer_usbblaster = { + .type = SPI_CONTROLLER_USBBLASTER, + .max_data_read = 256, + .max_data_write = 256, + .command = usbblaster_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, + .write_aai = default_spi_write_aai, +}; + +#endif