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