xref: /aosp_15_r20/external/flashrom/buspirate_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) 2009, 2010, 2011, 2012 Carl-Daniel Hailfinger
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 #include <stdio.h>
17*0d6140beSAndroid Build Coastguard Worker #include <strings.h>
18*0d6140beSAndroid Build Coastguard Worker #include <string.h>
19*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
20*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
21*0d6140beSAndroid Build Coastguard Worker #include <ctype.h>
22*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
23*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
24*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
25*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
26*0d6140beSAndroid Build Coastguard Worker 
27*0d6140beSAndroid Build Coastguard Worker /* Change this to #define if you want to test without a serial implementation */
28*0d6140beSAndroid Build Coastguard Worker #undef FAKE_COMMUNICATION
29*0d6140beSAndroid Build Coastguard Worker 
30*0d6140beSAndroid Build Coastguard Worker struct buspirate_speeds {
31*0d6140beSAndroid Build Coastguard Worker 	const char *name;
32*0d6140beSAndroid Build Coastguard Worker 	const int speed;
33*0d6140beSAndroid Build Coastguard Worker };
34*0d6140beSAndroid Build Coastguard Worker 
35*0d6140beSAndroid Build Coastguard Worker #define BP_DEFAULTBAUD 115200
36*0d6140beSAndroid Build Coastguard Worker 
37*0d6140beSAndroid Build Coastguard Worker #ifndef FAKE_COMMUNICATION
buspirate_serialport_setup(char * dev)38*0d6140beSAndroid Build Coastguard Worker static int buspirate_serialport_setup(char *dev)
39*0d6140beSAndroid Build Coastguard Worker {
40*0d6140beSAndroid Build Coastguard Worker 	/* 115200bps, 8 databits, no parity, 1 stopbit */
41*0d6140beSAndroid Build Coastguard Worker 	sp_fd = sp_openserport(dev, BP_DEFAULTBAUD);
42*0d6140beSAndroid Build Coastguard Worker 	if (sp_fd == SER_INV_FD)
43*0d6140beSAndroid Build Coastguard Worker 		return 1;
44*0d6140beSAndroid Build Coastguard Worker 	return 0;
45*0d6140beSAndroid Build Coastguard Worker }
46*0d6140beSAndroid Build Coastguard Worker #else
47*0d6140beSAndroid Build Coastguard Worker #define buspirate_serialport_setup(...) 0
48*0d6140beSAndroid Build Coastguard Worker #define serialport_shutdown(...) 0
49*0d6140beSAndroid Build Coastguard Worker #define serialport_write(...) 0
50*0d6140beSAndroid Build Coastguard Worker #define serialport_read(...) 0
51*0d6140beSAndroid Build Coastguard Worker #define sp_flush_incoming(...) 0
52*0d6140beSAndroid Build Coastguard Worker #endif
53*0d6140beSAndroid Build Coastguard Worker 
54*0d6140beSAndroid Build Coastguard Worker struct bp_spi_data {
55*0d6140beSAndroid Build Coastguard Worker 	unsigned char *commbuf;
56*0d6140beSAndroid Build Coastguard Worker 	int commbufsize;
57*0d6140beSAndroid Build Coastguard Worker };
58*0d6140beSAndroid Build Coastguard Worker 
buspirate_commbuf_grow(int bufsize,unsigned char ** bp_commbuf,int * bp_commbufsize)59*0d6140beSAndroid Build Coastguard Worker static int buspirate_commbuf_grow(int bufsize, unsigned char **bp_commbuf, int *bp_commbufsize)
60*0d6140beSAndroid Build Coastguard Worker {
61*0d6140beSAndroid Build Coastguard Worker 	unsigned char *tmpbuf;
62*0d6140beSAndroid Build Coastguard Worker 
63*0d6140beSAndroid Build Coastguard Worker 	/* Never shrink. realloc() calls are expensive. */
64*0d6140beSAndroid Build Coastguard Worker 	if (bufsize <= *bp_commbufsize)
65*0d6140beSAndroid Build Coastguard Worker 		return 0;
66*0d6140beSAndroid Build Coastguard Worker 
67*0d6140beSAndroid Build Coastguard Worker 	tmpbuf = realloc(*bp_commbuf, bufsize);
68*0d6140beSAndroid Build Coastguard Worker 	if (!tmpbuf) {
69*0d6140beSAndroid Build Coastguard Worker 		/* Keep the existing buffer because memory is already tight. */
70*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Out of memory!\n");
71*0d6140beSAndroid Build Coastguard Worker 		return ERROR_OOM;
72*0d6140beSAndroid Build Coastguard Worker 	}
73*0d6140beSAndroid Build Coastguard Worker 
74*0d6140beSAndroid Build Coastguard Worker 	*bp_commbuf = tmpbuf;
75*0d6140beSAndroid Build Coastguard Worker 	*bp_commbufsize = bufsize;
76*0d6140beSAndroid Build Coastguard Worker 	return 0;
77*0d6140beSAndroid Build Coastguard Worker }
78*0d6140beSAndroid Build Coastguard Worker 
buspirate_sendrecv(unsigned char * buf,unsigned int writecnt,unsigned int readcnt)79*0d6140beSAndroid Build Coastguard Worker static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt,
80*0d6140beSAndroid Build Coastguard Worker 			      unsigned int readcnt)
81*0d6140beSAndroid Build Coastguard Worker {
82*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
83*0d6140beSAndroid Build Coastguard Worker 	int ret = 0;
84*0d6140beSAndroid Build Coastguard Worker 
85*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: write %i, read %i ", __func__, writecnt, readcnt);
86*0d6140beSAndroid Build Coastguard Worker 	if (!writecnt && !readcnt) {
87*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Zero length command!\n");
88*0d6140beSAndroid Build Coastguard Worker 		return 1;
89*0d6140beSAndroid Build Coastguard Worker 	}
90*0d6140beSAndroid Build Coastguard Worker 	if (writecnt)
91*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("Sending");
92*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < writecnt; i++)
93*0d6140beSAndroid Build Coastguard Worker 		msg_pspew(" 0x%02x", buf[i]);
94*0d6140beSAndroid Build Coastguard Worker #ifdef FAKE_COMMUNICATION
95*0d6140beSAndroid Build Coastguard Worker 	/* Placate the caller for now. */
96*0d6140beSAndroid Build Coastguard Worker 	if (readcnt) {
97*0d6140beSAndroid Build Coastguard Worker 		buf[0] = 0x01;
98*0d6140beSAndroid Build Coastguard Worker 		memset(buf + 1, 0xff, readcnt - 1);
99*0d6140beSAndroid Build Coastguard Worker 	}
100*0d6140beSAndroid Build Coastguard Worker 	ret = 0;
101*0d6140beSAndroid Build Coastguard Worker #else
102*0d6140beSAndroid Build Coastguard Worker 	if (writecnt)
103*0d6140beSAndroid Build Coastguard Worker 		ret = serialport_write(buf, writecnt);
104*0d6140beSAndroid Build Coastguard Worker 	if (ret)
105*0d6140beSAndroid Build Coastguard Worker 		return ret;
106*0d6140beSAndroid Build Coastguard Worker 	if (readcnt)
107*0d6140beSAndroid Build Coastguard Worker 		ret = serialport_read(buf, readcnt);
108*0d6140beSAndroid Build Coastguard Worker 	if (ret)
109*0d6140beSAndroid Build Coastguard Worker 		return ret;
110*0d6140beSAndroid Build Coastguard Worker #endif
111*0d6140beSAndroid Build Coastguard Worker 	if (readcnt)
112*0d6140beSAndroid Build Coastguard Worker 		msg_pspew(", receiving");
113*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < readcnt; i++)
114*0d6140beSAndroid Build Coastguard Worker 		msg_pspew(" 0x%02x", buf[i]);
115*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("\n");
116*0d6140beSAndroid Build Coastguard Worker 	return 0;
117*0d6140beSAndroid Build Coastguard Worker }
118*0d6140beSAndroid Build Coastguard Worker 
buspirate_wait_for_string(unsigned char * buf,const char * key)119*0d6140beSAndroid Build Coastguard Worker static int buspirate_wait_for_string(unsigned char *buf, const char *key)
120*0d6140beSAndroid Build Coastguard Worker {
121*0d6140beSAndroid Build Coastguard Worker 	unsigned int keylen = strlen(key);
122*0d6140beSAndroid Build Coastguard Worker 	int ret;
123*0d6140beSAndroid Build Coastguard Worker 
124*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(buf, 0, keylen);
125*0d6140beSAndroid Build Coastguard Worker 	while (!ret) {
126*0d6140beSAndroid Build Coastguard Worker 		if (!memcmp(buf, key, keylen))
127*0d6140beSAndroid Build Coastguard Worker 			return 0;
128*0d6140beSAndroid Build Coastguard Worker 		memmove(buf, buf + 1, keylen - 1);
129*0d6140beSAndroid Build Coastguard Worker 		ret = buspirate_sendrecv(buf + keylen - 1, 0, 1);
130*0d6140beSAndroid Build Coastguard Worker 	}
131*0d6140beSAndroid Build Coastguard Worker 	return ret;
132*0d6140beSAndroid Build Coastguard Worker }
133*0d6140beSAndroid Build Coastguard Worker 
buspirate_spi_shutdown(void * data)134*0d6140beSAndroid Build Coastguard Worker static int buspirate_spi_shutdown(void *data)
135*0d6140beSAndroid Build Coastguard Worker {
136*0d6140beSAndroid Build Coastguard Worker 	struct bp_spi_data *bp_data = data;
137*0d6140beSAndroid Build Coastguard Worker 	unsigned char *const bp_commbuf = bp_data->commbuf;
138*0d6140beSAndroid Build Coastguard Worker 	int ret = 0, ret2 = 0;
139*0d6140beSAndroid Build Coastguard Worker 	/* No need to allocate a buffer here, we know that bp_commbuf is at least DEFAULT_BUFSIZE big. */
140*0d6140beSAndroid Build Coastguard Worker 
141*0d6140beSAndroid Build Coastguard Worker 	/* Exit raw SPI mode (enter raw bitbang mode) */
142*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x00;
143*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
144*0d6140beSAndroid Build Coastguard Worker 		goto out_shutdown;
145*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
146*0d6140beSAndroid Build Coastguard Worker 		goto out_shutdown;
147*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
148*0d6140beSAndroid Build Coastguard Worker 		goto out_shutdown;
149*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
150*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != '1') {
151*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
152*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
153*0d6140beSAndroid Build Coastguard Worker 		goto out_shutdown;
154*0d6140beSAndroid Build Coastguard Worker 	}
155*0d6140beSAndroid Build Coastguard Worker 	/* Reset Bus Pirate (return to user terminal) */
156*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x0f;
157*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, 1, 0);
158*0d6140beSAndroid Build Coastguard Worker 
159*0d6140beSAndroid Build Coastguard Worker out_shutdown:
160*0d6140beSAndroid Build Coastguard Worker 	/* Shut down serial port communication */
161*0d6140beSAndroid Build Coastguard Worker 	ret2 = serialport_shutdown(NULL);
162*0d6140beSAndroid Build Coastguard Worker 	/* Keep the oldest error, it is probably the best indicator. */
163*0d6140beSAndroid Build Coastguard Worker 	if (ret2 && !ret)
164*0d6140beSAndroid Build Coastguard Worker 		ret = ret2;
165*0d6140beSAndroid Build Coastguard Worker 
166*0d6140beSAndroid Build Coastguard Worker 	free(bp_commbuf);
167*0d6140beSAndroid Build Coastguard Worker 	if (ret)
168*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Bus Pirate shutdown failed.\n");
169*0d6140beSAndroid Build Coastguard Worker 	else
170*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Bus Pirate shutdown completed.\n");
171*0d6140beSAndroid Build Coastguard Worker 
172*0d6140beSAndroid Build Coastguard Worker 	free(data);
173*0d6140beSAndroid Build Coastguard Worker 	return ret;
174*0d6140beSAndroid Build Coastguard Worker }
175*0d6140beSAndroid Build Coastguard Worker 
176*0d6140beSAndroid Build Coastguard Worker static struct spi_master spi_master_buspirate = {
177*0d6140beSAndroid Build Coastguard Worker 	.features	= SPI_MASTER_4BA,
178*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= MAX_DATA_UNSPECIFIED,
179*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= MAX_DATA_UNSPECIFIED,
180*0d6140beSAndroid Build Coastguard Worker 	.command	= NULL,
181*0d6140beSAndroid Build Coastguard Worker 	.read		= default_spi_read,
182*0d6140beSAndroid Build Coastguard Worker 	.write_256	= default_spi_write_256,
183*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= buspirate_spi_shutdown,
184*0d6140beSAndroid Build Coastguard Worker };
185*0d6140beSAndroid Build Coastguard Worker 
186*0d6140beSAndroid Build Coastguard Worker static const struct buspirate_speeds spispeeds[] = {
187*0d6140beSAndroid Build Coastguard Worker 	{"30k",		0x0},
188*0d6140beSAndroid Build Coastguard Worker 	{"125k",	0x1},
189*0d6140beSAndroid Build Coastguard Worker 	{"250k",	0x2},
190*0d6140beSAndroid Build Coastguard Worker 	{"1M",		0x3},
191*0d6140beSAndroid Build Coastguard Worker 	{"2M",		0x4},
192*0d6140beSAndroid Build Coastguard Worker 	{"2.6M",	0x5},
193*0d6140beSAndroid Build Coastguard Worker 	{"4M",		0x6},
194*0d6140beSAndroid Build Coastguard Worker 	{"8M",		0x7},
195*0d6140beSAndroid Build Coastguard Worker 	{NULL,		0x0}
196*0d6140beSAndroid Build Coastguard Worker };
197*0d6140beSAndroid Build Coastguard Worker 
198*0d6140beSAndroid Build Coastguard Worker static const struct buspirate_speeds serialspeeds[] = {
199*0d6140beSAndroid Build Coastguard Worker 	{"115200",  115200},
200*0d6140beSAndroid Build Coastguard Worker 	{"230400",  230400},
201*0d6140beSAndroid Build Coastguard Worker 	{"250000",  250000},
202*0d6140beSAndroid Build Coastguard Worker 	{"2000000", 2000000},
203*0d6140beSAndroid Build Coastguard Worker 	{"2M",      2000000},
204*0d6140beSAndroid Build Coastguard Worker 	{NULL,      0}
205*0d6140beSAndroid Build Coastguard Worker };
206*0d6140beSAndroid Build Coastguard Worker 
buspirate_spi_send_command_v1(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)207*0d6140beSAndroid Build Coastguard Worker static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
208*0d6140beSAndroid Build Coastguard Worker 					 const unsigned char *writearr, unsigned char *readarr)
209*0d6140beSAndroid Build Coastguard Worker {
210*0d6140beSAndroid Build Coastguard Worker 	unsigned int i = 0;
211*0d6140beSAndroid Build Coastguard Worker 	int ret = 0;
212*0d6140beSAndroid Build Coastguard Worker 	struct bp_spi_data *bp_data = flash->mst->spi.data;
213*0d6140beSAndroid Build Coastguard Worker 
214*0d6140beSAndroid Build Coastguard Worker 	if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
215*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
216*0d6140beSAndroid Build Coastguard Worker 
217*0d6140beSAndroid Build Coastguard Worker 	/* 3 bytes extra for CS#, len, CS#. */
218*0d6140beSAndroid Build Coastguard Worker 	if (buspirate_commbuf_grow(writecnt + readcnt + 3, &bp_data->commbuf, &bp_data->commbufsize))
219*0d6140beSAndroid Build Coastguard Worker 		return ERROR_OOM;
220*0d6140beSAndroid Build Coastguard Worker 
221*0d6140beSAndroid Build Coastguard Worker 	unsigned char *const bp_commbuf = bp_data->commbuf;
222*0d6140beSAndroid Build Coastguard Worker 
223*0d6140beSAndroid Build Coastguard Worker 	/* Assert CS# */
224*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = 0x02;
225*0d6140beSAndroid Build Coastguard Worker 
226*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
227*0d6140beSAndroid Build Coastguard Worker 	memcpy(bp_commbuf + i, writearr, writecnt);
228*0d6140beSAndroid Build Coastguard Worker 	i += writecnt;
229*0d6140beSAndroid Build Coastguard Worker 	memset(bp_commbuf + i, 0, readcnt);
230*0d6140beSAndroid Build Coastguard Worker 
231*0d6140beSAndroid Build Coastguard Worker 	i += readcnt;
232*0d6140beSAndroid Build Coastguard Worker 	/* De-assert CS# */
233*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = 0x03;
234*0d6140beSAndroid Build Coastguard Worker 
235*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, i, i);
236*0d6140beSAndroid Build Coastguard Worker 
237*0d6140beSAndroid Build Coastguard Worker 	if (ret) {
238*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Bus Pirate communication error!\n");
239*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
240*0d6140beSAndroid Build Coastguard Worker 	}
241*0d6140beSAndroid Build Coastguard Worker 
242*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 0x01) {
243*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while lowering CS#!\n");
244*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
245*0d6140beSAndroid Build Coastguard Worker 	}
246*0d6140beSAndroid Build Coastguard Worker 
247*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[1] != 0x01) {
248*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while reading/writing SPI!\n");
249*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
250*0d6140beSAndroid Build Coastguard Worker 	}
251*0d6140beSAndroid Build Coastguard Worker 
252*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[i - 1] != 0x01) {
253*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while raising CS#!\n");
254*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
255*0d6140beSAndroid Build Coastguard Worker 	}
256*0d6140beSAndroid Build Coastguard Worker 
257*0d6140beSAndroid Build Coastguard Worker 	/* Skip CS#, length, writearr. */
258*0d6140beSAndroid Build Coastguard Worker 	memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
259*0d6140beSAndroid Build Coastguard Worker 
260*0d6140beSAndroid Build Coastguard Worker 	return ret;
261*0d6140beSAndroid Build Coastguard Worker }
262*0d6140beSAndroid Build Coastguard Worker 
buspirate_spi_send_command_v2(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)263*0d6140beSAndroid Build Coastguard Worker static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
264*0d6140beSAndroid Build Coastguard Worker 					 const unsigned char *writearr, unsigned char *readarr)
265*0d6140beSAndroid Build Coastguard Worker {
266*0d6140beSAndroid Build Coastguard Worker 	int i = 0, ret = 0;
267*0d6140beSAndroid Build Coastguard Worker 	struct bp_spi_data *bp_data = flash->mst->spi.data;
268*0d6140beSAndroid Build Coastguard Worker 
269*0d6140beSAndroid Build Coastguard Worker 	if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
270*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
271*0d6140beSAndroid Build Coastguard Worker 
272*0d6140beSAndroid Build Coastguard Worker 	/* 5 bytes extra for command, writelen, readlen.
273*0d6140beSAndroid Build Coastguard Worker 	 * 1 byte extra for Ack/Nack.
274*0d6140beSAndroid Build Coastguard Worker 	 */
275*0d6140beSAndroid Build Coastguard Worker 	if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1), &bp_data->commbuf, &bp_data->commbufsize))
276*0d6140beSAndroid Build Coastguard Worker 		return ERROR_OOM;
277*0d6140beSAndroid Build Coastguard Worker 
278*0d6140beSAndroid Build Coastguard Worker 	unsigned char *const bp_commbuf = bp_data->commbuf;
279*0d6140beSAndroid Build Coastguard Worker 
280*0d6140beSAndroid Build Coastguard Worker 	/* Combined SPI write/read. */
281*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = 0x04;
282*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = (writecnt >> 8) & 0xff;
283*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = writecnt & 0xff;
284*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = (readcnt >> 8) & 0xff;
285*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i++] = readcnt & 0xff;
286*0d6140beSAndroid Build Coastguard Worker 	memcpy(bp_commbuf + i, writearr, writecnt);
287*0d6140beSAndroid Build Coastguard Worker 
288*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, i + writecnt, 1 + readcnt);
289*0d6140beSAndroid Build Coastguard Worker 
290*0d6140beSAndroid Build Coastguard Worker 	if (ret) {
291*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Bus Pirate communication error!\n");
292*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
293*0d6140beSAndroid Build Coastguard Worker 	}
294*0d6140beSAndroid Build Coastguard Worker 
295*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 0x01) {
296*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while sending SPI write/read!\n");
297*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
298*0d6140beSAndroid Build Coastguard Worker 	}
299*0d6140beSAndroid Build Coastguard Worker 
300*0d6140beSAndroid Build Coastguard Worker 	/* Skip Ack. */
301*0d6140beSAndroid Build Coastguard Worker 	memcpy(readarr, bp_commbuf + 1, readcnt);
302*0d6140beSAndroid Build Coastguard Worker 
303*0d6140beSAndroid Build Coastguard Worker 	return ret;
304*0d6140beSAndroid Build Coastguard Worker }
305*0d6140beSAndroid Build Coastguard Worker 
306*0d6140beSAndroid Build Coastguard Worker #define BP_FWVERSION(a,b)	((a) << 8 | (b))
307*0d6140beSAndroid Build Coastguard Worker #define BP_HWVERSION(a,b)	BP_FWVERSION(a,b)
308*0d6140beSAndroid Build Coastguard Worker 
309*0d6140beSAndroid Build Coastguard Worker /**
310*0d6140beSAndroid Build Coastguard Worker  * The Bus Pirate's PIC microcontroller supports custom baud rates by manually specifying a
311*0d6140beSAndroid Build Coastguard Worker  * clock divisor that can be calculated with the formula (16000000 / (4 * baud)) - 1.
312*0d6140beSAndroid Build Coastguard Worker  */
313*0d6140beSAndroid Build Coastguard Worker #define BP_DIVISOR(baud) ((4000000/(baud)) - 1)
314*0d6140beSAndroid Build Coastguard Worker 
buspirate_spi_init(const struct programmer_cfg * cfg)315*0d6140beSAndroid Build Coastguard Worker static int buspirate_spi_init(const struct programmer_cfg *cfg)
316*0d6140beSAndroid Build Coastguard Worker {
317*0d6140beSAndroid Build Coastguard Worker 	char *tmp;
318*0d6140beSAndroid Build Coastguard Worker 	char *dev;
319*0d6140beSAndroid Build Coastguard Worker 	int i;
320*0d6140beSAndroid Build Coastguard Worker 	int cnt;
321*0d6140beSAndroid Build Coastguard Worker 	unsigned int fw_version_major = 0;
322*0d6140beSAndroid Build Coastguard Worker 	unsigned int fw_version_minor = 0;
323*0d6140beSAndroid Build Coastguard Worker 	unsigned int hw_version_major = 0;
324*0d6140beSAndroid Build Coastguard Worker 	unsigned int hw_version_minor = 0;
325*0d6140beSAndroid Build Coastguard Worker 	int spispeed = 0x7;
326*0d6140beSAndroid Build Coastguard Worker 	int serialspeed_index = -1;
327*0d6140beSAndroid Build Coastguard Worker 	int ret = 0;
328*0d6140beSAndroid Build Coastguard Worker 	bool hiz = false;
329*0d6140beSAndroid Build Coastguard Worker 	bool pullup = false;
330*0d6140beSAndroid Build Coastguard Worker 	bool psu = false;
331*0d6140beSAndroid Build Coastguard Worker 	bool aux = true;
332*0d6140beSAndroid Build Coastguard Worker 	unsigned char *bp_commbuf;
333*0d6140beSAndroid Build Coastguard Worker 	int bp_commbufsize;
334*0d6140beSAndroid Build Coastguard Worker 
335*0d6140beSAndroid Build Coastguard Worker 	dev = extract_programmer_param_str(cfg, "dev");
336*0d6140beSAndroid Build Coastguard Worker 	if (dev && !strlen(dev)) {
337*0d6140beSAndroid Build Coastguard Worker 		free(dev);
338*0d6140beSAndroid Build Coastguard Worker 		dev = NULL;
339*0d6140beSAndroid Build Coastguard Worker 	}
340*0d6140beSAndroid Build Coastguard Worker 	if (!dev) {
341*0d6140beSAndroid Build Coastguard Worker 		msg_perr("No serial device given. Use flashrom -p buspirate_spi:dev=/dev/ttyUSB0\n");
342*0d6140beSAndroid Build Coastguard Worker 		return 1;
343*0d6140beSAndroid Build Coastguard Worker 	}
344*0d6140beSAndroid Build Coastguard Worker 
345*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "spispeed");
346*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
347*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; spispeeds[i].name; i++) {
348*0d6140beSAndroid Build Coastguard Worker 			if (!strncasecmp(spispeeds[i].name, tmp, strlen(spispeeds[i].name))) {
349*0d6140beSAndroid Build Coastguard Worker 				spispeed = spispeeds[i].speed;
350*0d6140beSAndroid Build Coastguard Worker 				break;
351*0d6140beSAndroid Build Coastguard Worker 			}
352*0d6140beSAndroid Build Coastguard Worker 		}
353*0d6140beSAndroid Build Coastguard Worker 		if (!spispeeds[i].name)
354*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid SPI speed, using default.\n");
355*0d6140beSAndroid Build Coastguard Worker 	}
356*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
357*0d6140beSAndroid Build Coastguard Worker 
358*0d6140beSAndroid Build Coastguard Worker 	/* Extract serialspeed parameter */
359*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "serialspeed");
360*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
361*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; serialspeeds[i].name; i++) {
362*0d6140beSAndroid Build Coastguard Worker 			if (!strncasecmp(serialspeeds[i].name, tmp, strlen(serialspeeds[i].name))) {
363*0d6140beSAndroid Build Coastguard Worker 				serialspeed_index = i;
364*0d6140beSAndroid Build Coastguard Worker 				break;
365*0d6140beSAndroid Build Coastguard Worker 			}
366*0d6140beSAndroid Build Coastguard Worker 		}
367*0d6140beSAndroid Build Coastguard Worker 		if (!serialspeeds[i].name)
368*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid serial speed %s, using default.\n", tmp);
369*0d6140beSAndroid Build Coastguard Worker 	}
370*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
371*0d6140beSAndroid Build Coastguard Worker 
372*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "pullups");
373*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
374*0d6140beSAndroid Build Coastguard Worker 		if (strcasecmp("on", tmp) == 0) {
375*0d6140beSAndroid Build Coastguard Worker 			pullup = true;
376*0d6140beSAndroid Build Coastguard Worker 		} else if (strcasecmp("off", tmp) == 0) {
377*0d6140beSAndroid Build Coastguard Worker 			; // ignore
378*0d6140beSAndroid Build Coastguard Worker 		} else {
379*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid pullups state. Use on/off.\n");
380*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
381*0d6140beSAndroid Build Coastguard Worker 			return 1;
382*0d6140beSAndroid Build Coastguard Worker 		}
383*0d6140beSAndroid Build Coastguard Worker 	}
384*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
385*0d6140beSAndroid Build Coastguard Worker 
386*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "hiz");
387*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
388*0d6140beSAndroid Build Coastguard Worker 		if (strcasecmp("on", tmp) == 0) {
389*0d6140beSAndroid Build Coastguard Worker 			hiz = true;
390*0d6140beSAndroid Build Coastguard Worker 		} else if (strcasecmp("off", tmp) == 0) {
391*0d6140beSAndroid Build Coastguard Worker 			if (pullup) {
392*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Invalid combination: pullups=on & hiz=off at same time is not possible.\n");
393*0d6140beSAndroid Build Coastguard Worker 				free(tmp);
394*0d6140beSAndroid Build Coastguard Worker 				return 1;
395*0d6140beSAndroid Build Coastguard Worker 			} else {
396*0d6140beSAndroid Build Coastguard Worker 				; // ignore
397*0d6140beSAndroid Build Coastguard Worker 			}
398*0d6140beSAndroid Build Coastguard Worker 		} else {
399*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid hiz state. Use on/off.\n");
400*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
401*0d6140beSAndroid Build Coastguard Worker 			return 1;
402*0d6140beSAndroid Build Coastguard Worker 		}
403*0d6140beSAndroid Build Coastguard Worker 	}
404*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
405*0d6140beSAndroid Build Coastguard Worker 
406*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "psus");
407*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
408*0d6140beSAndroid Build Coastguard Worker 		if (strcasecmp("on", tmp) == 0) {
409*0d6140beSAndroid Build Coastguard Worker 			psu = true;
410*0d6140beSAndroid Build Coastguard Worker 		} else if (strcasecmp("off", tmp) == 0) {
411*0d6140beSAndroid Build Coastguard Worker 			; // ignore
412*0d6140beSAndroid Build Coastguard Worker 		} else {
413*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid psus state. Use on/off.\n");
414*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
415*0d6140beSAndroid Build Coastguard Worker 			return 1;
416*0d6140beSAndroid Build Coastguard Worker 		}
417*0d6140beSAndroid Build Coastguard Worker 	}
418*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
419*0d6140beSAndroid Build Coastguard Worker 
420*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "aux");
421*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
422*0d6140beSAndroid Build Coastguard Worker 		if (strcasecmp("high", tmp) == 0)
423*0d6140beSAndroid Build Coastguard Worker 			; /* Default */
424*0d6140beSAndroid Build Coastguard Worker 		else if (strcasecmp("low", tmp) == 0)
425*0d6140beSAndroid Build Coastguard Worker 			aux = false;
426*0d6140beSAndroid Build Coastguard Worker 		else
427*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid AUX state, driving high by default.\n");
428*0d6140beSAndroid Build Coastguard Worker 	}
429*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
430*0d6140beSAndroid Build Coastguard Worker 
431*0d6140beSAndroid Build Coastguard Worker 	/* Default buffer size is 19: 16 bytes data, 3 bytes control. */
432*0d6140beSAndroid Build Coastguard Worker #define DEFAULT_BUFSIZE (16 + 3)
433*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf = malloc(DEFAULT_BUFSIZE);
434*0d6140beSAndroid Build Coastguard Worker 	if (!bp_commbuf) {
435*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Out of memory!\n");
436*0d6140beSAndroid Build Coastguard Worker 		free(dev);
437*0d6140beSAndroid Build Coastguard Worker 		return ERROR_OOM;
438*0d6140beSAndroid Build Coastguard Worker 	}
439*0d6140beSAndroid Build Coastguard Worker 	bp_commbufsize = DEFAULT_BUFSIZE;
440*0d6140beSAndroid Build Coastguard Worker 
441*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_serialport_setup(dev);
442*0d6140beSAndroid Build Coastguard Worker 	free(dev);
443*0d6140beSAndroid Build Coastguard Worker 	if (ret) {
444*0d6140beSAndroid Build Coastguard Worker 		free(bp_commbuf);
445*0d6140beSAndroid Build Coastguard Worker 		return ret;
446*0d6140beSAndroid Build Coastguard Worker 	}
447*0d6140beSAndroid Build Coastguard Worker 
448*0d6140beSAndroid Build Coastguard Worker 
449*0d6140beSAndroid Build Coastguard Worker 	struct bp_spi_data *bp_data = calloc(1, sizeof(*bp_data));
450*0d6140beSAndroid Build Coastguard Worker 	if (!bp_data) {
451*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unable to allocate space for SPI master data\n");
452*0d6140beSAndroid Build Coastguard Worker 		free(bp_commbuf);
453*0d6140beSAndroid Build Coastguard Worker 		return 1;
454*0d6140beSAndroid Build Coastguard Worker 	}
455*0d6140beSAndroid Build Coastguard Worker 	bp_data->commbuf = bp_commbuf;
456*0d6140beSAndroid Build Coastguard Worker 	bp_data->commbufsize = bp_commbufsize;
457*0d6140beSAndroid Build Coastguard Worker 
458*0d6140beSAndroid Build Coastguard Worker 	/* This is the brute force version, but it should work.
459*0d6140beSAndroid Build Coastguard Worker 	 * It is likely to fail if a previous flashrom run was aborted during a write with the new SPI commands
460*0d6140beSAndroid Build Coastguard Worker 	 * in firmware v5.5 because that firmware may wait for up to 4096 bytes of input before responding to
461*0d6140beSAndroid Build Coastguard Worker 	 * 0x00 again. The obvious workaround (sending 4096 bytes of \0) may cause significant startup delays.
462*0d6140beSAndroid Build Coastguard Worker 	 */
463*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 20; i++) {
464*0d6140beSAndroid Build Coastguard Worker 		/* Enter raw bitbang mode */
465*0d6140beSAndroid Build Coastguard Worker 		bp_commbuf[0] = 0x00;
466*0d6140beSAndroid Build Coastguard Worker 		/* Send the command, don't read the response. */
467*0d6140beSAndroid Build Coastguard Worker 		ret = buspirate_sendrecv(bp_commbuf, 1, 0);
468*0d6140beSAndroid Build Coastguard Worker 		if (ret)
469*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
470*0d6140beSAndroid Build Coastguard Worker 		/* The old way to handle responses from a Bus Pirate already in BBIO mode was to flush any
471*0d6140beSAndroid Build Coastguard Worker 		 * response which came in over serial. Unfortunately that does not work reliably on Linux
472*0d6140beSAndroid Build Coastguard Worker 		 * with FTDI USB-serial.
473*0d6140beSAndroid Build Coastguard Worker 		 */
474*0d6140beSAndroid Build Coastguard Worker 		//sp_flush_incoming();
475*0d6140beSAndroid Build Coastguard Worker 		/* The Bus Pirate can't handle UART input buffer overflow in BBIO mode, and sending a sequence
476*0d6140beSAndroid Build Coastguard Worker 		 * of 0x00 too fast apparently triggers such an UART input buffer overflow.
477*0d6140beSAndroid Build Coastguard Worker 		 */
478*0d6140beSAndroid Build Coastguard Worker 		internal_sleep(10000);
479*0d6140beSAndroid Build Coastguard Worker 	}
480*0d6140beSAndroid Build Coastguard Worker 	/* We know that 20 commands of \0 should elicit at least one BBIO1 response. */
481*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
482*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
483*0d6140beSAndroid Build Coastguard Worker 
484*0d6140beSAndroid Build Coastguard Worker 	/* Reset the Bus Pirate. */
485*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x0f;
486*0d6140beSAndroid Build Coastguard Worker 	/* Send the command, don't read the response. */
487*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
488*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
489*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "irate ")))
490*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
491*0d6140beSAndroid Build Coastguard Worker 	/* Read the hardware version string. Last byte of the buffer is reserved for \0. */
492*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
493*0d6140beSAndroid Build Coastguard Worker 		if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
494*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
495*0d6140beSAndroid Build Coastguard Worker 		if (strchr("\r\n\t ", bp_commbuf[i]))
496*0d6140beSAndroid Build Coastguard Worker 			break;
497*0d6140beSAndroid Build Coastguard Worker 	}
498*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i] = '\0';
499*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Detected Bus Pirate hardware ");
500*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 'v')
501*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("(unknown version number format)");
502*0d6140beSAndroid Build Coastguard Worker 	else if (!strchr("0123456789", bp_commbuf[1]))
503*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("(unknown version number format)");
504*0d6140beSAndroid Build Coastguard Worker 	else {
505*0d6140beSAndroid Build Coastguard Worker 		hw_version_major = strtoul((char *)bp_commbuf + 1, &tmp, 10);
506*0d6140beSAndroid Build Coastguard Worker 		while ((*tmp != '\0') && !strchr("0123456789", *tmp))
507*0d6140beSAndroid Build Coastguard Worker 			tmp++;
508*0d6140beSAndroid Build Coastguard Worker 		hw_version_minor = strtoul(tmp, NULL, 10);
509*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%u.%u", hw_version_major, hw_version_minor);
510*0d6140beSAndroid Build Coastguard Worker 	}
511*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2(" (\"%s\")", bp_commbuf);
512*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("\n");
513*0d6140beSAndroid Build Coastguard Worker 
514*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "irmware ")))
515*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
516*0d6140beSAndroid Build Coastguard Worker 	/* Read the firmware version string. Last byte of the buffer is reserved for \0. */
517*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
518*0d6140beSAndroid Build Coastguard Worker 		if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
519*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
520*0d6140beSAndroid Build Coastguard Worker 		if (strchr("\r\n\t ", bp_commbuf[i]))
521*0d6140beSAndroid Build Coastguard Worker 			break;
522*0d6140beSAndroid Build Coastguard Worker 	}
523*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[i] = '\0';
524*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Detected Bus Pirate firmware ");
525*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 'v')
526*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("(unknown version number format)");
527*0d6140beSAndroid Build Coastguard Worker 	else if (!strchr("0123456789", bp_commbuf[1]))
528*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("(unknown version number format)");
529*0d6140beSAndroid Build Coastguard Worker 	else {
530*0d6140beSAndroid Build Coastguard Worker 		fw_version_major = strtoul((char *)bp_commbuf + 1, &tmp, 10);
531*0d6140beSAndroid Build Coastguard Worker 		while ((*tmp != '\0') && !strchr("0123456789", *tmp))
532*0d6140beSAndroid Build Coastguard Worker 			tmp++;
533*0d6140beSAndroid Build Coastguard Worker 		fw_version_minor = strtoul(tmp, NULL, 10);
534*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%u.%u", fw_version_major, fw_version_minor);
535*0d6140beSAndroid Build Coastguard Worker 	}
536*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2(" (\"%s\")", bp_commbuf);
537*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("\n");
538*0d6140beSAndroid Build Coastguard Worker 
539*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
540*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
541*0d6140beSAndroid Build Coastguard Worker 
542*0d6140beSAndroid Build Coastguard Worker 	/* Tell the user about missing SPI binary mode in firmware 2.3 and older. */
543*0d6140beSAndroid Build Coastguard Worker 	if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(2, 4)) {
544*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Bus Pirate firmware 2.3 and older does not support binary SPI access.\n");
545*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Please upgrade to the latest firmware (at least 2.4).\n");
546*0d6140beSAndroid Build Coastguard Worker 		ret = SPI_PROGRAMMER_ERROR;
547*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
548*0d6140beSAndroid Build Coastguard Worker 	}
549*0d6140beSAndroid Build Coastguard Worker 
550*0d6140beSAndroid Build Coastguard Worker 	/* Use fast SPI mode in firmware 5.5 and newer. */
551*0d6140beSAndroid Build Coastguard Worker 	if (BP_FWVERSION(fw_version_major, fw_version_minor) >= BP_FWVERSION(5, 5)) {
552*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Using SPI command set v2.\n");
553*0d6140beSAndroid Build Coastguard Worker 		/* Sensible default buffer size. */
554*0d6140beSAndroid Build Coastguard Worker 		if (buspirate_commbuf_grow(260 + 5, &bp_commbuf, &bp_commbufsize)) {
555*0d6140beSAndroid Build Coastguard Worker 			ret = ERROR_OOM;
556*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
557*0d6140beSAndroid Build Coastguard Worker 		}
558*0d6140beSAndroid Build Coastguard Worker 		bp_data->commbuf = bp_commbuf;
559*0d6140beSAndroid Build Coastguard Worker 		bp_data->commbufsize = bp_commbufsize;
560*0d6140beSAndroid Build Coastguard Worker 		spi_master_buspirate.max_data_read = 2048;
561*0d6140beSAndroid Build Coastguard Worker 		spi_master_buspirate.max_data_write = 256;
562*0d6140beSAndroid Build Coastguard Worker 		spi_master_buspirate.command = buspirate_spi_send_command_v2;
563*0d6140beSAndroid Build Coastguard Worker 	} else {
564*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Bus Pirate firmware 5.4 and older does not support fast SPI access.\n");
565*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Reading/writing a flash chip may take hours.\n");
566*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("It is recommended to upgrade to firmware 5.5 or newer.\n");
567*0d6140beSAndroid Build Coastguard Worker 		/* Sensible default buffer size. */
568*0d6140beSAndroid Build Coastguard Worker 		if (buspirate_commbuf_grow(16 + 3, &bp_commbuf, &bp_commbufsize)) {
569*0d6140beSAndroid Build Coastguard Worker 			ret = ERROR_OOM;
570*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
571*0d6140beSAndroid Build Coastguard Worker 		}
572*0d6140beSAndroid Build Coastguard Worker 		bp_data->commbuf = bp_commbuf;
573*0d6140beSAndroid Build Coastguard Worker 		bp_data->commbufsize = bp_commbufsize;
574*0d6140beSAndroid Build Coastguard Worker 		spi_master_buspirate.max_data_read = 12;
575*0d6140beSAndroid Build Coastguard Worker 		spi_master_buspirate.max_data_write = 12;
576*0d6140beSAndroid Build Coastguard Worker 		spi_master_buspirate.command = buspirate_spi_send_command_v1;
577*0d6140beSAndroid Build Coastguard Worker 	}
578*0d6140beSAndroid Build Coastguard Worker 
579*0d6140beSAndroid Build Coastguard Worker 	/* Workaround for broken speed settings in firmware 6.1 and older. */
580*0d6140beSAndroid Build Coastguard Worker 	if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(6, 2))
581*0d6140beSAndroid Build Coastguard Worker 		if (spispeed > 0x4) {
582*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Bus Pirate firmware 6.1 and older does not support SPI speeds above 2 MHz. "
583*0d6140beSAndroid Build Coastguard Worker 				 "Limiting speed to 2 MHz.\n");
584*0d6140beSAndroid Build Coastguard Worker 			msg_pinfo("It is recommended to upgrade to firmware 6.2 or newer.\n");
585*0d6140beSAndroid Build Coastguard Worker 			spispeed = 0x4;
586*0d6140beSAndroid Build Coastguard Worker 		}
587*0d6140beSAndroid Build Coastguard Worker 
588*0d6140beSAndroid Build Coastguard Worker 	/* This works because speeds numbering starts at 0 and is contiguous. */
589*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
590*0d6140beSAndroid Build Coastguard Worker 
591*0d6140beSAndroid Build Coastguard Worker 	/* Set 2M baud serial speed by default on hardware 3.0 and newer if a custom speed was not set */
592*0d6140beSAndroid Build Coastguard Worker 	if (serialspeed_index == -1 && BP_HWVERSION(hw_version_major, hw_version_minor) >= BP_HWVERSION(3, 0)) {
593*0d6140beSAndroid Build Coastguard Worker 		serialspeed_index = ARRAY_SIZE(serialspeeds) - 2;
594*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Bus Pirate v3 or newer detected. Set serial speed to 2M baud.\n");
595*0d6140beSAndroid Build Coastguard Worker 	}
596*0d6140beSAndroid Build Coastguard Worker 
597*0d6140beSAndroid Build Coastguard Worker 	/* Set custom serial speed if specified */
598*0d6140beSAndroid Build Coastguard Worker 	if (serialspeed_index != -1) {
599*0d6140beSAndroid Build Coastguard Worker 		if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(5, 5)) {
600*0d6140beSAndroid Build Coastguard Worker 			/* This feature requires firmware 5.5 or newer */
601*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Bus Pirate firmware 5.4 and older does not support custom serial speeds."
602*0d6140beSAndroid Build Coastguard Worker 				 "Using default speed of 115200 baud.\n");
603*0d6140beSAndroid Build Coastguard Worker 		} else if (serialspeeds[serialspeed_index].speed != BP_DEFAULTBAUD) {
604*0d6140beSAndroid Build Coastguard Worker 			/* Set the serial speed to match the user's choice if it doesn't already */
605*0d6140beSAndroid Build Coastguard Worker 
606*0d6140beSAndroid Build Coastguard Worker 			if (BP_HWVERSION(hw_version_major, hw_version_minor) < BP_HWVERSION(3, 0))
607*0d6140beSAndroid Build Coastguard Worker 				msg_pwarn("Increased serial speeds may not work on older (<3.0) Bus Pirates."
608*0d6140beSAndroid Build Coastguard Worker 					" Continue at your own risk.\n");
609*0d6140beSAndroid Build Coastguard Worker 
610*0d6140beSAndroid Build Coastguard Worker 			/* Enter baud rate configuration mode */
611*0d6140beSAndroid Build Coastguard Worker 			cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "b\n");
612*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
613*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
614*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_wait_for_string(bp_commbuf, ">")))
615*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
616*0d6140beSAndroid Build Coastguard Worker 
617*0d6140beSAndroid Build Coastguard Worker 			/* Enter manual clock divisor entry mode */
618*0d6140beSAndroid Build Coastguard Worker 			cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "10\n");
619*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
620*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
621*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_wait_for_string(bp_commbuf, ">")))
622*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
623*0d6140beSAndroid Build Coastguard Worker 
624*0d6140beSAndroid Build Coastguard Worker 			/* Set the clock divisor to the value calculated from the user's input */
625*0d6140beSAndroid Build Coastguard Worker 			cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "%d\n",
626*0d6140beSAndroid Build Coastguard Worker 				BP_DIVISOR(serialspeeds[serialspeed_index].speed));
627*0d6140beSAndroid Build Coastguard Worker 
628*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
629*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
630*0d6140beSAndroid Build Coastguard Worker 			sleep(1);
631*0d6140beSAndroid Build Coastguard Worker 
632*0d6140beSAndroid Build Coastguard Worker 			/* Reconfigure the host's serial baud rate to the new value */
633*0d6140beSAndroid Build Coastguard Worker 			if ((ret = serialport_config(sp_fd, serialspeeds[serialspeed_index].speed))) {
634*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Unable to configure system baud rate to specified value.");
635*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
636*0d6140beSAndroid Build Coastguard Worker 			}
637*0d6140beSAndroid Build Coastguard Worker 
638*0d6140beSAndroid Build Coastguard Worker 			/* Return to the main prompt */
639*0d6140beSAndroid Build Coastguard Worker 			bp_commbuf[0] = ' ';
640*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
641*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
642*0d6140beSAndroid Build Coastguard Worker 			if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
643*0d6140beSAndroid Build Coastguard Worker 				goto init_err_cleanup_exit;
644*0d6140beSAndroid Build Coastguard Worker 
645*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Serial speed is %d baud\n", serialspeeds[serialspeed_index].speed);
646*0d6140beSAndroid Build Coastguard Worker 		}
647*0d6140beSAndroid Build Coastguard Worker 
648*0d6140beSAndroid Build Coastguard Worker 	}
649*0d6140beSAndroid Build Coastguard Worker 
650*0d6140beSAndroid Build Coastguard Worker 
651*0d6140beSAndroid Build Coastguard Worker 
652*0d6140beSAndroid Build Coastguard Worker 	/* Enter raw bitbang mode */
653*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 20; i++) {
654*0d6140beSAndroid Build Coastguard Worker 		bp_commbuf[0] = 0x00;
655*0d6140beSAndroid Build Coastguard Worker 		if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
656*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
657*0d6140beSAndroid Build Coastguard Worker 	}
658*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
659*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
660*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
661*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
662*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
663*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != '1') {
664*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
665*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
666*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
667*0d6140beSAndroid Build Coastguard Worker 	}
668*0d6140beSAndroid Build Coastguard Worker 	/* Enter raw SPI mode */
669*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x01;
670*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, 1, 0);
671*0d6140beSAndroid Build Coastguard Worker 	if (ret)
672*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
673*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_wait_for_string(bp_commbuf, "SPI")))
674*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
675*0d6140beSAndroid Build Coastguard Worker 	if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
676*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
677*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Raw SPI mode version %c\n", bp_commbuf[0]);
678*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != '1') {
679*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Can't handle raw SPI mode version %c!\n", bp_commbuf[0]);
680*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
681*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
682*0d6140beSAndroid Build Coastguard Worker 	}
683*0d6140beSAndroid Build Coastguard Worker 
684*0d6140beSAndroid Build Coastguard Worker 	/* Initial setup (SPI peripherals config): Enable power, CS high */
685*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x40 | 0x09;
686*0d6140beSAndroid Build Coastguard Worker 	if (pullup) {
687*0d6140beSAndroid Build Coastguard Worker 		bp_commbuf[0] |= (1 << 2);
688*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling pull-up resistors.\n");
689*0d6140beSAndroid Build Coastguard Worker 	}
690*0d6140beSAndroid Build Coastguard Worker 	if (psu) {
691*0d6140beSAndroid Build Coastguard Worker 		bp_commbuf[0] |= (1 << 3);
692*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling PSUs.\n");
693*0d6140beSAndroid Build Coastguard Worker 	}
694*0d6140beSAndroid Build Coastguard Worker 	if (aux) {
695*0d6140beSAndroid Build Coastguard Worker 		bp_commbuf[0] |= (1 << 1);
696*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Driving AUX high.\n");
697*0d6140beSAndroid Build Coastguard Worker 	} else {
698*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Driving AUX low.\n");
699*0d6140beSAndroid Build Coastguard Worker 	}
700*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, 1, 1);
701*0d6140beSAndroid Build Coastguard Worker 	if (ret)
702*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
703*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 0x01) {
704*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while setting power/CS/AUX(/Pull-up resistors)!\n");
705*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
706*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
707*0d6140beSAndroid Build Coastguard Worker 	}
708*0d6140beSAndroid Build Coastguard Worker 
709*0d6140beSAndroid Build Coastguard Worker 	/* Set SPI speed */
710*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x60 | spispeed;
711*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, 1, 1);
712*0d6140beSAndroid Build Coastguard Worker 	if (ret)
713*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
714*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 0x01) {
715*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while setting SPI speed!\n");
716*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
717*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
718*0d6140beSAndroid Build Coastguard Worker 	}
719*0d6140beSAndroid Build Coastguard Worker 
720*0d6140beSAndroid Build Coastguard Worker 	/* Set SPI config: output type, idle, clock edge, sample */
721*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x80 | 0xa;
722*0d6140beSAndroid Build Coastguard Worker 	if (pullup || hiz) {
723*0d6140beSAndroid Build Coastguard Worker 		bp_commbuf[0] &= ~(1 << 3);
724*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Pull-ups or HiZ enabled, so using HiZ pin output! (Open-Drain mode)\n");
725*0d6140beSAndroid Build Coastguard Worker 	}
726*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, 1, 1);
727*0d6140beSAndroid Build Coastguard Worker 	if (ret)
728*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
729*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 0x01) {
730*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while setting SPI config!\n");
731*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
732*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
733*0d6140beSAndroid Build Coastguard Worker 	}
734*0d6140beSAndroid Build Coastguard Worker 
735*0d6140beSAndroid Build Coastguard Worker 	/* De-assert CS# */
736*0d6140beSAndroid Build Coastguard Worker 	bp_commbuf[0] = 0x03;
737*0d6140beSAndroid Build Coastguard Worker 	ret = buspirate_sendrecv(bp_commbuf, 1, 1);
738*0d6140beSAndroid Build Coastguard Worker 	if (ret)
739*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
740*0d6140beSAndroid Build Coastguard Worker 	if (bp_commbuf[0] != 0x01) {
741*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Protocol error while raising CS#!\n");
742*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
743*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
744*0d6140beSAndroid Build Coastguard Worker 	}
745*0d6140beSAndroid Build Coastguard Worker 
746*0d6140beSAndroid Build Coastguard Worker 	return register_spi_master(&spi_master_buspirate, bp_data);
747*0d6140beSAndroid Build Coastguard Worker 
748*0d6140beSAndroid Build Coastguard Worker init_err_cleanup_exit:
749*0d6140beSAndroid Build Coastguard Worker 	buspirate_spi_shutdown(bp_data);
750*0d6140beSAndroid Build Coastguard Worker 	return ret;
751*0d6140beSAndroid Build Coastguard Worker }
752*0d6140beSAndroid Build Coastguard Worker 
753*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_buspirate_spi = {
754*0d6140beSAndroid Build Coastguard Worker 	.name			= "buspirate_spi",
755*0d6140beSAndroid Build Coastguard Worker 	.type			= OTHER,
756*0d6140beSAndroid Build Coastguard Worker 				/* FIXME */
757*0d6140beSAndroid Build Coastguard Worker 	.devs.note		= "Dangerous Prototypes Bus Pirate\n",
758*0d6140beSAndroid Build Coastguard Worker 	.init			= buspirate_spi_init,
759*0d6140beSAndroid Build Coastguard Worker };
760