blob: 86fd5736e1bd0a8c788aeee54184a2f337b2e3ef [file] [log] [blame]
James Lairdc60de0e2013-03-27 13:00:23 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2012 James Laird <jhl@mafipulation.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * Device should be connected as per "active serial" mode:
22 *
23 * +---------+------+-----------+
24 * | SPI | Pin | Altera |
25 * +---------+------+-----------+
26 * | SCLK | 1 | DCLK |
27 * | GND | 2,10 | GND |
28 * | VCC | 4 | VCC(TRGT) |
29 * | MISO | 7 | DATAOUT |
30 * | /CS | 8 | nCS |
31 * | MOSI | 9 | ASDI |
32 * +---------+------+-----------+
33 *
34 * See also the USB-Blaster Download Cable User Guide: http://www.altera.com/literature/ug/ug_usb_blstr.pdf
35 */
36
37#if CONFIG_USBBLASTER_SPI == 1
38
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42#include <ctype.h>
43#include <ftdi.h>
44#include "flash.h"
45#include "programmer.h"
46#include "spi.h"
47
48/* Please keep sorted by vendor ID, then device ID. */
49#define ALTERA_VID 0x09fb
50#define ALTERA_USBBLASTER_PID 0x6001
51
52const struct dev_entry devs_usbblasterspi[] = {
53 {ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "Altera", "USB-Blaster"},
54
55 {}
56};
57
58static const struct spi_programmer spi_programmer_usbblaster;
59
60static struct ftdi_context ftdic;
61
62// command bytes
63#define BIT_BYTE (1<<7) // byte mode (rather than bitbang)
64#define BIT_READ (1<<6) // read request
65#define BIT_LED (1<<5)
66#define BIT_CS (1<<3)
67#define BIT_TMS (1<<1)
68#define BIT_CLK (1<<0)
69
70#define BUF_SIZE 64
71
72/* The programmer shifts bits in the wrong order for SPI, so we use this method to reverse the bits when needed.
73 * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
74uint8_t reverse(uint8_t b)
75{
76 return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
77}
78
79
80/* Returns 0 upon success, a negative number upon errors. */
81int usbblaster_spi_init(void)
82{
83 uint8_t buf[BUF_SIZE + 1];
84
85 if (ftdi_init(&ftdic) < 0)
86 return -1;
87
88 if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
89 msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str);
90 return -1;
91 }
92
93 if (ftdi_usb_reset(&ftdic) < 0) {
94 msg_perr("USB-Blaster reset failed\n");
95 return -1;
96 }
97
98 if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
99 msg_perr("USB-Blaster set latency timer failed\n");
100 return -1;
101 }
102
103 if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
104 ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
105 msg_perr("USB-Blaster set chunk size failed\n");
106 return -1;
107 }
108
109 memset(buf, 0, sizeof(buf));
110 buf[sizeof(buf)-1] = BIT_LED | BIT_CS;
111 if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
112 msg_perr("USB-Blaster reset write failed\n");
113 return -1;
114 }
115 if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
116 msg_perr("USB-Blaster reset read failed\n");
117 return -1;
118 }
119
120 register_spi_programmer(&spi_programmer_usbblaster);
121 return 0;
122}
123
124static int send_write(unsigned int writecnt, const unsigned char *writearr)
125{
126 int i;
127 uint8_t buf[BUF_SIZE];
128
129 memset(buf, 0, sizeof(buf));
130 while (writecnt) {
131 unsigned int n_write = min(writecnt, BUF_SIZE - 1);
132 msg_pspew("writing %d-byte packet\n", n_write);
133
134 buf[0] = BIT_BYTE | (uint8_t)n_write;
135 for (i = 0; i < n_write; i++) {
136 buf[i+1] = reverse(writearr[i]);
137 }
138 if (ftdi_write_data(&ftdic, buf, n_write + 1) < 0) {
139 msg_perr("USB-Blaster write failed\n");
140 return -1;
141 }
142
143 writearr += n_write;
144 writecnt -= n_write;
145 }
146 return 0;
147}
148
149static int send_read(unsigned int readcnt, unsigned char *readarr)
150{
151 int i;
152 unsigned int n_read;
153 uint8_t buf[BUF_SIZE];
154 memset(buf, 0, sizeof(buf));
155
156 n_read = readcnt;
157 while (n_read) {
158 unsigned int payload_size = min(n_read, BUF_SIZE - 1);
159 msg_pspew("reading %d-byte packet\n", payload_size);
160
161 buf[0] = BIT_BYTE | BIT_READ | (uint8_t)payload_size;
162 if (ftdi_write_data(&ftdic, buf, payload_size + 1) < 0) {
163 msg_perr("USB-Blaster write failed\n");
164 return -1;
165 }
166 n_read -= payload_size;
167 };
168
169 n_read = readcnt;
170 while (n_read) {
171 int ret = ftdi_read_data(&ftdic, readarr, n_read);
172 if (ret < 0) {
173 msg_perr("USB-Blaster read failed\n");
174 return -1;
175 }
176 for (i = 0; i < ret; i++) {
177 readarr[i] = reverse(readarr[i]);
178 }
179 n_read -= ret;
180 readarr += ret;
181 }
182 return 0;
183}
184
185/* Returns 0 upon success, a negative number upon errors. */
186static int usbblaster_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
187 const unsigned char *writearr, unsigned char *readarr)
188{
189 uint8_t cmd;
190 int ret = 0;
191
192 cmd = BIT_LED; // asserts /CS
193 if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
194 msg_perr("USB-Blaster enable chip select failed\n");
195 ret = -1;
196 }
197
198 if (!ret && writecnt)
199 ret = send_write(writecnt, writearr);
200
201 if (!ret && readcnt)
202 ret = send_read(readcnt, readarr);
203
204 cmd = BIT_CS;
205 if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
206 msg_perr("USB-Blaster disable chip select failed\n");
207 ret = -1;
208 }
209
210 return ret;
211}
212
213
214static const struct spi_programmer spi_programmer_usbblaster = {
215 .type = SPI_CONTROLLER_USBBLASTER,
216 .max_data_read = 256,
217 .max_data_write = 256,
218 .command = usbblaster_spi_send_command,
219 .multicommand = default_spi_send_multicommand,
220 .read = default_spi_read,
221 .write_256 = default_spi_write_256,
222 .write_aai = default_spi_write_aai,
223};
224
225#endif