blob: 0a9e952472993cf28a799a20ea684f2797ae09af [file] [log] [blame]
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +00001/*
2 * This file is part of the flashrom project.
3 *
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +00004 * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <stdio.h>
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000021#include <string.h>
22#include <stdlib.h>
23#include <ctype.h>
Carl-Daniel Hailfingerd2f007f2010-09-16 22:34:25 +000024#include <unistd.h>
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000025#include "flash.h"
Sean Nelson14ba6682010-02-26 05:48:29 +000026#include "chipdrivers.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000027#include "programmer.h"
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000028#include "spi.h"
29
30/* Change this to #define if you want to test without a serial implementation */
31#undef FAKE_COMMUNICATION
32
33#ifndef FAKE_COMMUNICATION
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000034static int buspirate_serialport_setup(char *dev)
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000035{
36 /* 115200bps, 8 databits, no parity, 1 stopbit */
37 sp_fd = sp_openserport(dev, 115200);
38 return 0;
39}
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000040#else
41#define buspirate_serialport_setup(...) 0
Carl-Daniel Hailfingerefa151e2010-01-06 16:09:10 +000042#define serialport_shutdown(...) 0
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000043#define serialport_write(...) 0
44#define serialport_read(...) 0
Patrick Georgi3b6237d2010-01-06 19:09:40 +000045#define sp_flush_incoming(...) 0
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000046#endif
47
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000048static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000049{
50 int i, ret = 0;
51
Sean Nelson84f7bce2010-01-09 23:56:41 +000052 msg_pspew("%s: write %i, read %i ", __func__, writecnt, readcnt);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000053 if (!writecnt && !readcnt) {
Sean Nelson84f7bce2010-01-09 23:56:41 +000054 msg_perr("Zero length command!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000055 return 1;
56 }
Sean Nelson84f7bce2010-01-09 23:56:41 +000057 msg_pspew("Sending");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000058 for (i = 0; i < writecnt; i++)
Sean Nelson84f7bce2010-01-09 23:56:41 +000059 msg_pspew(" 0x%02x", buf[i]);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000060#ifdef FAKE_COMMUNICATION
61 /* Placate the caller for now. */
62 if (readcnt) {
63 buf[0] = 0x01;
64 memset(buf + 1, 0xff, readcnt - 1);
65 }
66 ret = 0;
67#else
68 if (writecnt)
69 ret = serialport_write(buf, writecnt);
70 if (ret)
71 return ret;
72 if (readcnt)
73 ret = serialport_read(buf, readcnt);
74 if (ret)
75 return ret;
76#endif
Sean Nelson84f7bce2010-01-09 23:56:41 +000077 msg_pspew(", receiving");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000078 for (i = 0; i < readcnt; i++)
Sean Nelson84f7bce2010-01-09 23:56:41 +000079 msg_pspew(" 0x%02x", buf[i]);
80 msg_pspew("\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +000081 return 0;
82}
83
Michael Karcherb9dbe482011-05-11 17:07:07 +000084static int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
85 const unsigned char *writearr, unsigned char *readarr);
86
87static const struct spi_programmer spi_programmer_buspirate = {
88 .type = SPI_CONTROLLER_BUSPIRATE,
89 .max_data_read = 12,
90 .max_data_write = 12,
91 .command = buspirate_spi_send_command,
92 .multicommand = default_spi_send_multicommand,
93 .read = default_spi_read,
94 .write_256 = default_spi_write_256,
95};
96
Carl-Daniel Hailfingerd5b28fa2009-11-24 18:27:10 +000097static const struct buspirate_spispeeds spispeeds[] = {
98 {"30k", 0x0},
99 {"125k", 0x1},
100 {"250k", 0x2},
101 {"1M", 0x3},
102 {"2M", 0x4},
103 {"2.6M", 0x5},
104 {"4M", 0x6},
105 {"8M", 0x7},
106 {NULL, 0x0}
107};
108
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000109int buspirate_spi_init(void)
110{
111 unsigned char buf[512];
112 int ret = 0;
113 int i;
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000114 char *dev = NULL;
Carl-Daniel Hailfingerd5b28fa2009-11-24 18:27:10 +0000115 char *speed = NULL;
116 int spispeed = 0x7;
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000117
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000118 dev = extract_programmer_param("dev");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000119 if (!dev || !strlen(dev)) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000120 msg_perr("No serial device given. Use flashrom -p "
Carl-Daniel Hailfinger71127722010-05-31 15:27:27 +0000121 "buspirate_spi:dev=/dev/ttyUSB0\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000122 return 1;
123 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000124
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000125 speed = extract_programmer_param("spispeed");
Carl-Daniel Hailfingerd5b28fa2009-11-24 18:27:10 +0000126 if (speed) {
127 for (i = 0; spispeeds[i].name; i++)
128 if (!strncasecmp(spispeeds[i].name, speed,
129 strlen(spispeeds[i].name))) {
130 spispeed = spispeeds[i].speed;
131 break;
132 }
133 if (!spispeeds[i].name)
Sean Nelson84f7bce2010-01-09 23:56:41 +0000134 msg_perr("Invalid SPI speed, using default.\n");
Carl-Daniel Hailfingerd5b28fa2009-11-24 18:27:10 +0000135 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000136 free(speed);
137
Carl-Daniel Hailfingerd5b28fa2009-11-24 18:27:10 +0000138 /* This works because speeds numbering starts at 0 and is contiguous. */
Sean Nelson84f7bce2010-01-09 23:56:41 +0000139 msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000140
141 ret = buspirate_serialport_setup(dev);
142 if (ret)
143 return ret;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000144 free(dev);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000145
146 /* This is the brute force version, but it should work. */
147 for (i = 0; i < 19; i++) {
148 /* Enter raw bitbang mode */
149 buf[0] = 0x00;
150 /* Send the command, don't read the response. */
151 ret = buspirate_sendrecv(buf, 1, 0);
152 if (ret)
153 return ret;
154 /* Read any response and discard it. */
Patrick Georgi3b6237d2010-01-06 19:09:40 +0000155 sp_flush_incoming();
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000156 }
Carl-Daniel Hailfingerd2f007f2010-09-16 22:34:25 +0000157 /* USB is slow. The Bus Pirate is even slower. Apparently the flush
158 * action above is too fast or too early. Some stuff still remains in
159 * the pipe after the flush above, and one additional flush is not
160 * sufficient either. Use a 1.5 ms delay inside the loop to make
161 * mostly sure that at least one USB frame had time to arrive.
162 * Looping only 5 times is not sufficient and causes the
163 * ocassional failure.
164 * Folding the delay into the loop above is not reliable either.
165 */
166 for (i = 0; i < 10; i++) {
167 usleep(1500);
168 /* Read any response and discard it. */
169 sp_flush_incoming();
170 }
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000171 /* Enter raw bitbang mode */
172 buf[0] = 0x00;
173 ret = buspirate_sendrecv(buf, 1, 5);
174 if (ret)
175 return ret;
176 if (memcmp(buf, "BBIO", 4)) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000177 msg_perr("Entering raw bitbang mode failed!\n");
Carl-Daniel Hailfingerd2f007f2010-09-16 22:34:25 +0000178 msg_pdbg("Got %02x%02x%02x%02x%02x\n",
179 buf[0], buf[1], buf[2], buf[3], buf[4]);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000180 return 1;
181 }
Sean Nelson84f7bce2010-01-09 23:56:41 +0000182 msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000183 if (buf[4] != '1') {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000184 msg_perr("Can't handle raw bitbang mode version %c!\n",
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000185 buf[4]);
186 return 1;
187 }
188 /* Enter raw SPI mode */
189 buf[0] = 0x01;
190 ret = buspirate_sendrecv(buf, 1, 4);
Carl-Daniel Hailfingerd2f007f2010-09-16 22:34:25 +0000191 if (ret)
192 return ret;
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000193 if (memcmp(buf, "SPI", 3)) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000194 msg_perr("Entering raw SPI mode failed!\n");
Carl-Daniel Hailfingerd2f007f2010-09-16 22:34:25 +0000195 msg_pdbg("Got %02x%02x%02x%02x\n",
196 buf[0], buf[1], buf[2], buf[3]);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000197 return 1;
198 }
Sean Nelson84f7bce2010-01-09 23:56:41 +0000199 msg_pdbg("Raw SPI mode version %c\n", buf[3]);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000200 if (buf[3] != '1') {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000201 msg_perr("Can't handle raw SPI mode version %c!\n",
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000202 buf[3]);
203 return 1;
204 }
205
206 /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
207 buf[0] = 0x40 | 0xb;
208 ret = buspirate_sendrecv(buf, 1, 1);
209 if (ret)
210 return 1;
211 if (buf[0] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000212 msg_perr("Protocol error while setting power/CS/AUX!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000213 return 1;
214 }
215
Carl-Daniel Hailfingerd5b28fa2009-11-24 18:27:10 +0000216 /* Set SPI speed */
217 buf[0] = 0x60 | spispeed;
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000218 ret = buspirate_sendrecv(buf, 1, 1);
219 if (ret)
220 return 1;
221 if (buf[0] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000222 msg_perr("Protocol error while setting SPI speed!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000223 return 1;
224 }
225
226 /* Set SPI config: output type, idle, clock edge, sample */
227 buf[0] = 0x80 | 0xa;
228 ret = buspirate_sendrecv(buf, 1, 1);
229 if (ret)
230 return 1;
231 if (buf[0] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000232 msg_perr("Protocol error while setting SPI config!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000233 return 1;
234 }
235
236 /* De-assert CS# */
237 buf[0] = 0x03;
238 ret = buspirate_sendrecv(buf, 1, 1);
239 if (ret)
240 return 1;
241 if (buf[0] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000242 msg_perr("Protocol error while raising CS#!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000243 return 1;
244 }
245
Michael Karcherb9dbe482011-05-11 17:07:07 +0000246 register_spi_programmer(&spi_programmer_buspirate);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000247
248 return 0;
249}
250
251int buspirate_spi_shutdown(void)
252{
253 unsigned char buf[5];
254 int ret = 0;
255
256 /* Exit raw SPI mode (enter raw bitbang mode) */
257 buf[0] = 0x00;
258 ret = buspirate_sendrecv(buf, 1, 5);
259 if (ret)
260 return ret;
261 if (memcmp(buf, "BBIO", 4)) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000262 msg_perr("Entering raw bitbang mode failed!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000263 return 1;
264 }
Sean Nelson84f7bce2010-01-09 23:56:41 +0000265 msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000266 if (buf[4] != '1') {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000267 msg_perr("Can't handle raw bitbang mode version %c!\n",
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000268 buf[4]);
269 return 1;
270 }
271 /* Reset Bus Pirate (return to user terminal) */
272 buf[0] = 0x0f;
273 ret = buspirate_sendrecv(buf, 1, 0);
274 if (ret)
275 return ret;
276
277 /* Shut down serial port communication */
Carl-Daniel Hailfingerefa151e2010-01-06 16:09:10 +0000278 ret = serialport_shutdown();
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000279 if (ret)
280 return ret;
Sean Nelson84f7bce2010-01-09 23:56:41 +0000281 msg_pdbg("Bus Pirate shutdown completed.\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000282
283 return 0;
284}
285
Michael Karcherb9dbe482011-05-11 17:07:07 +0000286static int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000287 const unsigned char *writearr, unsigned char *readarr)
288{
289 static unsigned char *buf = NULL;
290 int i = 0, ret = 0;
291
292 if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
293 return SPI_INVALID_LENGTH;
294
Carl-Daniel Hailfinger04e18be2010-07-29 16:24:09 +0000295 /* 3 bytes extra for CS#, len, CS#. */
296 buf = realloc(buf, writecnt + readcnt + 3);
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000297 if (!buf) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000298 msg_perr("Out of memory!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000299 exit(1); // -1
300 }
301
302 /* Assert CS# */
303 buf[i++] = 0x02;
Carl-Daniel Hailfinger04e18be2010-07-29 16:24:09 +0000304
305 buf[i++] = 0x10 | (writecnt + readcnt - 1);
306 memcpy(buf + i, writearr, writecnt);
307 i += writecnt;
308 memset(buf + i, 0, readcnt);
309
310 i += readcnt;
311 /* De-assert CS# */
312 buf[i++] = 0x03;
313
314 ret = buspirate_sendrecv(buf, i, i);
315
316 if (ret) {
317 msg_perr("Bus Pirate communication error!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000318 return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger04e18be2010-07-29 16:24:09 +0000319 }
320
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000321 if (buf[0] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000322 msg_perr("Protocol error while lowering CS#!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000323 return SPI_GENERIC_ERROR;
324 }
325
Carl-Daniel Hailfinger04e18be2010-07-29 16:24:09 +0000326 if (buf[1] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000327 msg_perr("Protocol error while reading/writing SPI!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000328 return SPI_GENERIC_ERROR;
329 }
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000330
Carl-Daniel Hailfinger04e18be2010-07-29 16:24:09 +0000331 if (buf[i - 1] != 0x01) {
Sean Nelson84f7bce2010-01-09 23:56:41 +0000332 msg_perr("Protocol error while raising CS#!\n");
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000333 return SPI_GENERIC_ERROR;
334 }
335
Carl-Daniel Hailfinger04e18be2010-07-29 16:24:09 +0000336 /* Skip CS#, length, writearr. */
337 memcpy(readarr, buf + 2 + writecnt, readcnt);
338
Carl-Daniel Hailfinger5cca01f2009-11-24 00:20:03 +0000339 return ret;
340}