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(a)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(a)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. */
};