diff options
author | James Laird <jhl@mafipulation.org> | 2013-03-27 13:00:23 +0000 |
---|---|---|
committer | Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at> | 2013-03-27 13:00:23 +0000 |
commit | c60de0e87faa631887821892547f0554eed2727f (patch) | |
tree | 54b9eb93e87ead0498bdacd22f4a3cd3e0ffd2ae /usbblaster_spi.c | |
parent | 226037da3d274fdf65e477e9ef1082356830b2c7 (diff) | |
download | ast2050-flashrom-c60de0e87faa631887821892547f0554eed2727f.zip ast2050-flashrom-c60de0e87faa631887821892547f0554eed2727f.tar.gz |
Add Altera USB-Blaster SPI programmer
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 <jhl@mafipulation.org>
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Diffstat (limited to 'usbblaster_spi.c')
-rw-r--r-- | usbblaster_spi.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/usbblaster_spi.c b/usbblaster_spi.c new file mode 100644 index 0000000..86fd573 --- /dev/null +++ b/usbblaster_spi.c @@ -0,0 +1,225 @@ +/* + * 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 | 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <ftdi.h> +#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 |