Adds support for the Altera USB Blaster programming dongle in SPI mode. It has only been tested against a cheap clone ($10, unclear origin), and so is marked as not tested. It should also support several variants which are present on Altera dev boards (PID 6002,6003...), although I believe these are hardwired to their targets.
Signed-off-by: James Laird jhl@mafipulation.org Index: Makefile =================================================================== --- Makefile (revision 1548) +++ Makefile (working copy) @@ -84,7 +84,7 @@ else override CONFIG_SERPROG = 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 @@ -95,7 +95,12 @@ 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? ifeq ($(TARGET_OS), MinGW) @@ -196,7 +201,7 @@ 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 @@ -207,7 +212,12 @@ 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) ifeq ($(CONFIG_LINUX_SPI), yes) @@ -344,6 +354,9 @@ # 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
@@ -430,14 +443,31 @@ NEED_PCI := yes endif
+# This is a totally ugly hack. +WANT_LIBFTDI := no +HAVE_LIBFTDI := $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && echo "yes") 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 := 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 ($(WANT_LIBFTDI), yes) + FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") + FEATURE_LIBS += $(FTDILIBS) + endif +endif + ifeq ($(CONFIG_DUMMY), yes) FEATURE_CFLAGS += -D'CONFIG_DUMMY=1' PROGRAMMER_OBJS += dummyflasher.o @@ -700,7 +730,7 @@
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 && \ Index: README =================================================================== --- README (revision 1548) +++ README (working copy) @@ -45,8 +45,8 @@ 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:
Index: usbblaster_spi.c =================================================================== --- usbblaster_spi.c (revision 0) +++ usbblaster_spi.c (working copy) @@ -0,0 +1,258 @@ +/* + * 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) + +#define BITS_OTHER 0 + +// The programmer shifts bits in the wrong order for SPI. +static unsigned char reverse[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + + +/* 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; + } + unsigned char buf[65]; + memset(buf, 0, sizeof(buf)); + buf[sizeof(buf)-1] = BIT_LED | BITS_OTHER | 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; +} + +/* 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) +{ + unsigned char cmd; + unsigned char buf[64]; + unsigned char tms_state = 0; + int i; + // assert /CS + cmd = BIT_LED | BITS_OTHER; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + + while (writecnt) { + unsigned int n_write = writecnt; + if (n_write > 63) + n_write = 63; + + msg_pspew("writing %d-byte packet\n", n_write); + + cmd = BIT_BYTE | (unsigned char)n_write; + buf[0] = cmd; + 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; + } + + cmd = BIT_LED | BITS_OTHER | (tms_state ^= BIT_TMS); + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + writearr += n_write; + writecnt -= n_write; + } + + unsigned int n_readout = readcnt; + while (readcnt) { + unsigned int n_read = readcnt; + if (n_read > 63) + n_read = 63; + + cmd = BIT_BYTE | BIT_READ | (unsigned char)n_read; + buf[0] = cmd; + if (ftdi_write_data(&ftdic, buf, n_read + 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + cmd = BIT_LED | BITS_OTHER | (tms_state ^= BIT_TMS); + if (ftdi_write_data(&ftdic, &cmd, 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; + } + + cmd = BIT_LED | BIT_CS | BITS_OTHER; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + cmd = BIT_CS | BITS_OTHER; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + return 0; +} + + +static const struct spi_programmer spi_programmer_usbblaster = { + .type = SPI_CONTROLLER_USBBLASTER, + .max_data_read = 4096, + .max_data_write = 256, + .command = usbblaster_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, +}; + +#endif Index: programmer.h =================================================================== --- programmer.h (revision 1548) +++ programmer.h (working copy) @@ -87,6 +87,9 @@ #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. */ };
@@ -433,6 +436,11 @@ 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); @@ -514,6 +522,9 @@ #if CONFIG_SERPROG == 1 SPI_CONTROLLER_SERPROG, #endif +#if CONFIG_USBBLASTER_SPI == 1 + SPI_CONTROLLER_USBBLASTER, +#endif };
#define MAX_DATA_UNSPECIFIED 0 Index: print.c =================================================================== --- print.c (revision 1548) +++ print.c (working copy) @@ -538,6 +538,12 @@ 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); + /* FIXME */ + msg_ginfo("Altera USB Blaster cable\n"); +#endif }
#if CONFIG_INTERNAL == 1 Index: flashrom.c =================================================================== --- flashrom.c (revision 1548) +++ flashrom.c (working copy) @@ -262,6 +262,16 @@ }, #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 + {}, /* This entry corresponds to PROGRAMMER_INVALID. */ };