From c60de0e87faa631887821892547f0554eed2727f Mon Sep 17 00:00:00 2001 From: James Laird Date: Wed, 27 Mar 2013 13:00:23 +0000 Subject: Add Altera USB-Blaster SPI programmer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for the Altera USB-Blaster programming dongle in Active Serial (AS) mode. Tested on both original product and a clone dongle. Corresponding to flashrom svn r1658. Signed-off-by: James Laird Signed-off-by: Kyösti Mälkki Signed-off-by: Stefan Tauner Acked-by: Kyösti Mälkki Acked-by: Stefan Tauner --- Makefile | 30 +++++++- README | 4 +- flashrom.8 | 6 +- flashrom.c | 12 +++ programmer.h | 12 +++ usbblaster_spi.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 282 insertions(+), 7 deletions(-) create mode 100644 usbblaster_spi.c diff --git a/Makefile b/Makefile index b9489961..07fefc06 100644 --- a/Makefile +++ b/Makefile @@ -128,6 +128,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? @@ -240,6 +245,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) @@ -349,6 +359,9 @@ CONFIG_ATAHPT ?= no # Always enable FT2232 SPI dongles for now. CONFIG_FT2232_SPI ?= yes +# Always enable Altera USB-Blaster dongles for now. +CONFIG_USBBLASTER_SPI ?= yes + # Always enable dummy tracing for now. CONFIG_DUMMY ?= yes @@ -474,12 +487,23 @@ 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'") +NEED_FTDI := yes +PROGRAMMER_OBJS += ft2232_spi.o +endif + +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +# This is a totally ugly hack. +FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_USBBLASTER_SPI=1'") +NEED_FTDI := yes +PROGRAMMER_OBJS += usbblaster_spi.o +endif + +ifeq ($(NEED_FTDI), yes) +FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'") FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -PROGRAMMER_OBJS += ft2232_spi.o # We can't set NEED_USB here because that would transform libftdi auto-enabling # into a hard requirement for libusb, defeating the purpose of auto-enabling. endif @@ -799,7 +823,7 @@ export LINUX_SPI_TEST features: compiler @echo "FEATURES := yes" > .features.tmp -ifeq ($(CONFIG_FT2232_SPI), yes) +ifeq ($(NEED_FTDI), 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 8e812be2..7f24cca1 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.8 b/flashrom.8 index c6c518e6..feb70d69 100644 --- a/flashrom.8 +++ b/flashrom.8 @@ -220,6 +220,8 @@ bitbanging adapter) .sp .BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)" .sp +.BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)" +.sp Some programmers have optional or mandatory parameters which are described in detail in the .B PROGRAMMER SPECIFIC INFO @@ -837,7 +839,7 @@ needs TCP access to the network or userspace access to a serial port. .B buspirate_spi needs userspace access to a serial port. .sp -.BR dediprog " and " ft2232_spi +.BR dediprog ", " ft2232_spi " and " usbblaster_spi need access to the USB device via libusb. .sp .B dummy @@ -847,7 +849,7 @@ needs no access permissions at all. .BR gfxnvidia ", " drkaiser ", " satasii ", " satamv " and " atahpt have to be run as superuser/root, and need additional raw access permission. .sp -.BR serprog ", " buspirate_spi ", " dediprog " and " ft2232_spi +.BR serprog ", " buspirate_spi ", " dediprog ", " usbblaster_spi " and " ft2232_spi can be run as normal user on most operating systems if appropriate device permissions are set. .sp diff --git a/flashrom.c b/flashrom.c index 225b6f0e..6a117b21 100644 --- a/flashrom.c +++ b/flashrom.c @@ -308,6 +308,18 @@ const struct programmer_entry programmer_table[] = { }, #endif +#if CONFIG_USBBLASTER_SPI == 1 + { + .name = "usbblaster_spi", + .type = USB, + .devs.dev = devs_usbblasterspi, + .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/programmer.h b/programmer.h index 03a71d88..b10f5689 100644 --- a/programmer.h +++ b/programmer.h @@ -86,6 +86,9 @@ enum programmer { #endif #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. */ }; @@ -431,6 +434,12 @@ int ft2232_spi_init(void); extern const struct dev_entry devs_ft2232spi[]; #endif +/* usbblaster_spi.c */ +#if CONFIG_USBBLASTER_SPI == 1 +int usbblaster_spi_init(void); +extern const struct dev_entry devs_usbblasterspi[]; +#endif + /* rayer_spi.c */ #if CONFIG_RAYER_SPI == 1 int rayer_spi_init(void); @@ -509,6 +518,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 00000000..86fd5736 --- /dev/null +++ b/usbblaster_spi.c @@ -0,0 +1,225 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2012 James Laird + * + * 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 | DATAOUT | + * | /CS | 8 | nCS | + * | MOSI | 9 | ASDI | + * +---------+------+-----------+ + * + * See also the USB-Blaster Download Cable User Guide: http://www.altera.com/literature/ug/ug_usb_blstr.pdf + */ + +#if CONFIG_USBBLASTER_SPI == 1 + +#include +#include +#include +#include +#include +#include "flash.h" +#include "programmer.h" +#include "spi.h" + +/* Please keep sorted by vendor ID, then device ID. */ +#define ALTERA_VID 0x09fb +#define ALTERA_USBBLASTER_PID 0x6001 + +const struct dev_entry devs_usbblasterspi[] = { + {ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "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_TMS (1<<1) +#define BIT_CLK (1<<0) + +#define BUF_SIZE 64 + +/* The programmer shifts bits in the wrong order for SPI, so we use this method to reverse the bits when needed. + * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */ +uint8_t reverse(uint8_t b) +{ + return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; +} + + +/* Returns 0 upon success, a negative number upon errors. */ +int usbblaster_spi_init(void) +{ + uint8_t buf[BUF_SIZE + 1]; + + 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("USB-Blaster reset failed\n"); + return -1; + } + + if (ftdi_set_latency_timer(&ftdic, 2) < 0) { + msg_perr("USB-Blaster set latency timer failed\n"); + return -1; + } + + if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 || + ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) { + msg_perr("USB-Blaster set chunk size failed\n"); + return -1; + } + + memset(buf, 0, sizeof(buf)); + buf[sizeof(buf)-1] = BIT_LED | BIT_CS; + if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("USB-Blaster reset write failed\n"); + return -1; + } + if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("USB-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) +{ + int i; + uint8_t buf[BUF_SIZE]; + + memset(buf, 0, sizeof(buf)); + while (writecnt) { + unsigned int n_write = min(writecnt, BUF_SIZE - 1); + 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("USB-Blaster write failed\n"); + return -1; + } + + writearr += n_write; + writecnt -= n_write; + } + return 0; +} + +static int send_read(unsigned int readcnt, unsigned char *readarr) +{ + int i; + unsigned int n_read; + uint8_t buf[BUF_SIZE]; + memset(buf, 0, sizeof(buf)); + + n_read = readcnt; + while (n_read) { + unsigned int payload_size = min(n_read, BUF_SIZE - 1); + msg_pspew("reading %d-byte packet\n", payload_size); + + buf[0] = BIT_BYTE | BIT_READ | (uint8_t)payload_size; + if (ftdi_write_data(&ftdic, buf, payload_size + 1) < 0) { + msg_perr("USB-Blaster write failed\n"); + return -1; + } + n_read -= payload_size; + }; + + n_read = readcnt; + while (n_read) { + int ret = ftdi_read_data(&ftdic, readarr, n_read); + if (ret < 0) { + msg_perr("USB-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) +{ + uint8_t cmd; + int ret = 0; + + cmd = BIT_LED; // asserts /CS + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("USB-Blaster enable chip select 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("USB-Blaster disable chip select 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 -- cgit v1.2.3