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