blob: 36105c2901498dd3438d94dfa56c9764d1874e00 [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
James Lairdc60de0e2013-03-27 13:00:23 +000033#include <stdio.h>
34#include <string.h>
35#include <stdlib.h>
36#include <ctype.h>
37#include <ftdi.h>
38#include "flash.h"
39#include "programmer.h"
40#include "spi.h"
41
42/* Please keep sorted by vendor ID, then device ID. */
43#define ALTERA_VID 0x09fb
44#define ALTERA_USBBLASTER_PID 0x6001
45
Thomas Heijligencc853d82021-05-04 15:32:17 +020046static const struct dev_entry devs_usbblasterspi[] = {
James Lairdc60de0e2013-03-27 13:00:23 +000047 {ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "Altera", "USB-Blaster"},
48
Evgeny Zinoviev83c56b82019-11-05 17:47:43 +030049 {0}
James Lairdc60de0e2013-03-27 13:00:23 +000050};
51
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +000052static const struct spi_master spi_master_usbblaster;
James Lairdc60de0e2013-03-27 13:00:23 +000053
54static struct ftdi_context ftdic;
55
56// command bytes
57#define BIT_BYTE (1<<7) // byte mode (rather than bitbang)
58#define BIT_READ (1<<6) // read request
59#define BIT_LED (1<<5)
60#define BIT_CS (1<<3)
61#define BIT_TMS (1<<1)
62#define BIT_CLK (1<<0)
63
64#define BUF_SIZE 64
65
66/* The programmer shifts bits in the wrong order for SPI, so we use this method to reverse the bits when needed.
67 * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
Jacob Garberbeeb8bc2019-06-21 15:24:17 -060068static uint8_t reverse(uint8_t b)
James Lairdc60de0e2013-03-27 13:00:23 +000069{
70 return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
71}
72
73
74/* Returns 0 upon success, a negative number upon errors. */
Thomas Heijligencc853d82021-05-04 15:32:17 +020075static int usbblaster_spi_init(void)
James Lairdc60de0e2013-03-27 13:00:23 +000076{
Angel Pons7e134562021-06-07 13:29:13 +020077 uint8_t buf[BUF_SIZE + 1] = { 0 };
James Lairdc60de0e2013-03-27 13:00:23 +000078
79 if (ftdi_init(&ftdic) < 0)
80 return -1;
81
82 if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
83 msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str);
84 return -1;
85 }
86
87 if (ftdi_usb_reset(&ftdic) < 0) {
88 msg_perr("USB-Blaster reset failed\n");
89 return -1;
90 }
91
92 if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
93 msg_perr("USB-Blaster set latency timer failed\n");
94 return -1;
95 }
96
97 if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
98 ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
99 msg_perr("USB-Blaster set chunk size failed\n");
100 return -1;
101 }
102
James Lairdc60de0e2013-03-27 13:00:23 +0000103 buf[sizeof(buf)-1] = BIT_LED | BIT_CS;
104 if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
105 msg_perr("USB-Blaster reset write failed\n");
106 return -1;
107 }
108 if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
109 msg_perr("USB-Blaster reset read failed\n");
110 return -1;
111 }
112
Nico Huber5e08e3e2021-05-11 17:38:14 +0200113 register_spi_master(&spi_master_usbblaster, NULL);
James Lairdc60de0e2013-03-27 13:00:23 +0000114 return 0;
115}
116
117static int send_write(unsigned int writecnt, const unsigned char *writearr)
118{
Angel Pons7e134562021-06-07 13:29:13 +0200119 uint8_t buf[BUF_SIZE] = { 0 };
James Lairdc60de0e2013-03-27 13:00:23 +0000120
James Lairdc60de0e2013-03-27 13:00:23 +0000121 while (writecnt) {
Nico Huber519be662018-12-23 20:03:35 +0100122 unsigned int i;
James Lairdc60de0e2013-03-27 13:00:23 +0000123 unsigned int n_write = min(writecnt, BUF_SIZE - 1);
124 msg_pspew("writing %d-byte packet\n", n_write);
125
126 buf[0] = BIT_BYTE | (uint8_t)n_write;
127 for (i = 0; i < n_write; i++) {
128 buf[i+1] = reverse(writearr[i]);
129 }
130 if (ftdi_write_data(&ftdic, buf, n_write + 1) < 0) {
131 msg_perr("USB-Blaster write failed\n");
132 return -1;
133 }
134
135 writearr += n_write;
136 writecnt -= n_write;
137 }
138 return 0;
139}
140
141static int send_read(unsigned int readcnt, unsigned char *readarr)
142{
143 int i;
144 unsigned int n_read;
Angel Pons7e134562021-06-07 13:29:13 +0200145 uint8_t buf[BUF_SIZE] = { 0 };
James Lairdc60de0e2013-03-27 13:00:23 +0000146
147 n_read = readcnt;
148 while (n_read) {
149 unsigned int payload_size = min(n_read, BUF_SIZE - 1);
150 msg_pspew("reading %d-byte packet\n", payload_size);
151
152 buf[0] = BIT_BYTE | BIT_READ | (uint8_t)payload_size;
153 if (ftdi_write_data(&ftdic, buf, payload_size + 1) < 0) {
154 msg_perr("USB-Blaster write failed\n");
155 return -1;
156 }
157 n_read -= payload_size;
David Hendrickscdb290e2020-06-23 14:16:26 -0700158 }
James Lairdc60de0e2013-03-27 13:00:23 +0000159
160 n_read = readcnt;
161 while (n_read) {
162 int ret = ftdi_read_data(&ftdic, readarr, n_read);
163 if (ret < 0) {
164 msg_perr("USB-Blaster read failed\n");
165 return -1;
166 }
167 for (i = 0; i < ret; i++) {
168 readarr[i] = reverse(readarr[i]);
169 }
170 n_read -= ret;
171 readarr += ret;
172 }
173 return 0;
174}
175
176/* Returns 0 upon success, a negative number upon errors. */
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000177static int usbblaster_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
James Lairdc60de0e2013-03-27 13:00:23 +0000178 const unsigned char *writearr, unsigned char *readarr)
179{
180 uint8_t cmd;
181 int ret = 0;
182
183 cmd = BIT_LED; // asserts /CS
184 if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
185 msg_perr("USB-Blaster enable chip select failed\n");
186 ret = -1;
187 }
188
189 if (!ret && writecnt)
190 ret = send_write(writecnt, writearr);
191
192 if (!ret && readcnt)
193 ret = send_read(readcnt, readarr);
194
195 cmd = BIT_CS;
196 if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
197 msg_perr("USB-Blaster disable chip select failed\n");
198 ret = -1;
199 }
200
201 return ret;
202}
203
204
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000205static const struct spi_master spi_master_usbblaster = {
James Lairdc60de0e2013-03-27 13:00:23 +0000206 .max_data_read = 256,
207 .max_data_write = 256,
208 .command = usbblaster_spi_send_command,
209 .multicommand = default_spi_send_multicommand,
210 .read = default_spi_read,
211 .write_256 = default_spi_write_256,
212 .write_aai = default_spi_write_aai,
213};
214
Thomas Heijligencc853d82021-05-04 15:32:17 +0200215const struct programmer_entry programmer_usbblaster_spi = {
216 .name = "usbblaster_spi",
217 .type = USB,
218 .devs.dev = devs_usbblasterspi,
219 .init = usbblaster_spi_init,
220 .map_flash_region = fallback_map,
221 .unmap_flash_region = fallback_unmap,
222 .delay = internal_delay,
223};