blob: 115876e880abc767d2bd9cde93a338b7170fb749 [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.
James Lairdc60de0e2013-03-27 13:00:23 +000014 */
15
16/*
17 * Device should be connected as per "active serial" mode:
18 *
19 * +---------+------+-----------+
20 * | SPI | Pin | Altera |
21 * +---------+------+-----------+
22 * | SCLK | 1 | DCLK |
23 * | GND | 2,10 | GND |
24 * | VCC | 4 | VCC(TRGT) |
25 * | MISO | 7 | DATAOUT |
26 * | /CS | 8 | nCS |
27 * | MOSI | 9 | ASDI |
28 * +---------+------+-----------+
29 *
30 * See also the USB-Blaster Download Cable User Guide: http://www.altera.com/literature/ug/ug_usb_blstr.pdf
31 */
32
33#if CONFIG_USBBLASTER_SPI == 1
34
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38#include <ctype.h>
39#include <ftdi.h>
40#include "flash.h"
41#include "programmer.h"
42#include "spi.h"
43
44/* Please keep sorted by vendor ID, then device ID. */
45#define ALTERA_VID 0x09fb
46#define ALTERA_USBBLASTER_PID 0x6001
47
48const struct dev_entry devs_usbblasterspi[] = {
49 {ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "Altera", "USB-Blaster"},
50
Evgeny Zinoviev83c56b82019-11-05 17:47:43 +030051 {0}
James Lairdc60de0e2013-03-27 13:00:23 +000052};
53
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +100054struct usbblaster_spi_data {
55 struct ftdi_context ftdic;
56};
James Lairdc60de0e2013-03-27 13:00:23 +000057
58// command bytes
59#define BIT_BYTE (1<<7) // byte mode (rather than bitbang)
60#define BIT_READ (1<<6) // read request
61#define BIT_LED (1<<5)
62#define BIT_CS (1<<3)
63#define BIT_TMS (1<<1)
64#define BIT_CLK (1<<0)
65
66#define BUF_SIZE 64
67
68/* The programmer shifts bits in the wrong order for SPI, so we use this method to reverse the bits when needed.
69 * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
Jacob Garberbeeb8bc2019-06-21 15:24:17 -060070static uint8_t reverse(uint8_t b)
James Lairdc60de0e2013-03-27 13:00:23 +000071{
72 return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
73}
74
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +100075static int send_write(unsigned int writecnt, const unsigned char *writearr, struct ftdi_context ftdic)
James Lairdc60de0e2013-03-27 13:00:23 +000076{
James Lairdc60de0e2013-03-27 13:00:23 +000077 uint8_t buf[BUF_SIZE];
78
79 memset(buf, 0, sizeof(buf));
80 while (writecnt) {
Nico Huber519be662018-12-23 20:03:35 +010081 unsigned int i;
James Lairdc60de0e2013-03-27 13:00:23 +000082 unsigned int n_write = min(writecnt, BUF_SIZE - 1);
83 msg_pspew("writing %d-byte packet\n", n_write);
84
85 buf[0] = BIT_BYTE | (uint8_t)n_write;
86 for (i = 0; i < n_write; i++) {
87 buf[i+1] = reverse(writearr[i]);
88 }
89 if (ftdi_write_data(&ftdic, buf, n_write + 1) < 0) {
90 msg_perr("USB-Blaster write failed\n");
91 return -1;
92 }
93
94 writearr += n_write;
95 writecnt -= n_write;
96 }
97 return 0;
98}
99
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000100static int send_read(unsigned int readcnt, unsigned char *readarr, struct ftdi_context ftdic)
James Lairdc60de0e2013-03-27 13:00:23 +0000101{
102 int i;
103 unsigned int n_read;
104 uint8_t buf[BUF_SIZE];
105 memset(buf, 0, sizeof(buf));
106
107 n_read = readcnt;
108 while (n_read) {
109 unsigned int payload_size = min(n_read, BUF_SIZE - 1);
110 msg_pspew("reading %d-byte packet\n", payload_size);
111
112 buf[0] = BIT_BYTE | BIT_READ | (uint8_t)payload_size;
113 if (ftdi_write_data(&ftdic, buf, payload_size + 1) < 0) {
114 msg_perr("USB-Blaster write failed\n");
115 return -1;
116 }
117 n_read -= payload_size;
David Hendricks17d46372020-06-23 14:16:26 -0700118 }
James Lairdc60de0e2013-03-27 13:00:23 +0000119
120 n_read = readcnt;
121 while (n_read) {
122 int ret = ftdi_read_data(&ftdic, readarr, n_read);
123 if (ret < 0) {
124 msg_perr("USB-Blaster read failed\n");
125 return -1;
126 }
127 for (i = 0; i < ret; i++) {
128 readarr[i] = reverse(readarr[i]);
129 }
130 n_read -= ret;
131 readarr += ret;
132 }
133 return 0;
134}
135
136/* Returns 0 upon success, a negative number upon errors. */
Edward O'Callaghane4ddc362020-04-12 17:27:53 +1000137static int usbblaster_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
James Lairdc60de0e2013-03-27 13:00:23 +0000138 const unsigned char *writearr, unsigned char *readarr)
139{
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000140 struct usbblaster_spi_data *usbblaster_data = flash->mst->spi.data;
James Lairdc60de0e2013-03-27 13:00:23 +0000141 uint8_t cmd;
142 int ret = 0;
143
144 cmd = BIT_LED; // asserts /CS
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000145 if (ftdi_write_data(&usbblaster_data->ftdic, &cmd, 1) < 0) {
James Lairdc60de0e2013-03-27 13:00:23 +0000146 msg_perr("USB-Blaster enable chip select failed\n");
147 ret = -1;
148 }
149
150 if (!ret && writecnt)
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000151 ret = send_write(writecnt, writearr, usbblaster_data->ftdic);
James Lairdc60de0e2013-03-27 13:00:23 +0000152
153 if (!ret && readcnt)
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000154 ret = send_read(readcnt, readarr, usbblaster_data->ftdic);
James Lairdc60de0e2013-03-27 13:00:23 +0000155
156 cmd = BIT_CS;
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000157 if (ftdi_write_data(&usbblaster_data->ftdic, &cmd, 1) < 0) {
James Lairdc60de0e2013-03-27 13:00:23 +0000158 msg_perr("USB-Blaster disable chip select failed\n");
159 ret = -1;
160 }
161
162 return ret;
163}
164
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000165static int usbblaster_shutdown(void *data)
166{
167 free(data);
168 return 0;
169}
James Lairdc60de0e2013-03-27 13:00:23 +0000170
Nico Huber90739d12021-05-11 17:53:34 +0200171static const struct spi_master spi_master_usbblaster = {
James Lairdc60de0e2013-03-27 13:00:23 +0000172 .max_data_read = 256,
173 .max_data_write = 256,
174 .command = usbblaster_spi_send_command,
175 .multicommand = default_spi_send_multicommand,
176 .read = default_spi_read,
177 .write_256 = default_spi_write_256,
178 .write_aai = default_spi_write_aai,
179};
180
Anastasia Klimchuke7045832021-03-23 16:34:07 +1100181/* Returns 0 upon success, a negative number upon errors. */
182int usbblaster_spi_init(void)
183{
184 uint8_t buf[BUF_SIZE + 1];
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000185 struct ftdi_context ftdic;
186 struct usbblaster_spi_data *usbblaster_data;
Anastasia Klimchuke7045832021-03-23 16:34:07 +1100187
188 if (ftdi_init(&ftdic) < 0)
189 return -1;
190
191 if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
192 msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str);
193 return -1;
194 }
195
196 if (ftdi_usb_reset(&ftdic) < 0) {
197 msg_perr("USB-Blaster reset failed\n");
198 return -1;
199 }
200
201 if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
202 msg_perr("USB-Blaster set latency timer failed\n");
203 return -1;
204 }
205
206 if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
207 ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
208 msg_perr("USB-Blaster set chunk size failed\n");
209 return -1;
210 }
211
212 memset(buf, 0, sizeof(buf));
213 buf[sizeof(buf)-1] = BIT_LED | BIT_CS;
214 if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
215 msg_perr("USB-Blaster reset write failed\n");
216 return -1;
217 }
218 if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
219 msg_perr("USB-Blaster reset read failed\n");
220 return -1;
221 }
222
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000223 usbblaster_data = calloc(1, sizeof(*usbblaster_data));
224 if (!usbblaster_data) {
225 msg_perr("Unable to allocate space for SPI master data\n");
226 return -1;
227 }
228 usbblaster_data->ftdic = ftdic;
Anastasia Klimchuke1e9e2b2021-05-11 11:27:55 +1000229
230 if (register_shutdown(usbblaster_shutdown, usbblaster_data)) {
231 free(usbblaster_data);
232 return -1;
233 }
Nico Huber90739d12021-05-11 17:53:34 +0200234 register_spi_master(&spi_master_usbblaster, usbblaster_data);
Anastasia Klimchuke7045832021-03-23 16:34:07 +1100235 return 0;
236}
237
James Lairdc60de0e2013-03-27 13:00:23 +0000238#endif