source: trunk/buspirate_spi.c @ 1474

Revision 1474, 8.5 KB checked in by hailfinger, 7 weeks ago (diff)

Add struct flashctx * parameter to all functions accessing flash chips.

All programmer access function prototypes except init have been made
static and moved to the respective file.

A few internal functions in flash chip drivers had chipaddr parameters
which are no longer needed.

The lines touched by flashctx changes have been adjusted to 80 columns
except in header files.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>
Acked-by: Michael Karcher <flashrom@…>

Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
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>
21#include <string.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include <unistd.h>
25#include "flash.h"
26#include "programmer.h"
27#include "spi.h"
28
29/* Change this to #define if you want to test without a serial implementation */
30#undef FAKE_COMMUNICATION
31
32struct buspirate_spispeeds {
33        const char *name;
34        const int speed;
35};
36
37#ifndef FAKE_COMMUNICATION
38static int buspirate_serialport_setup(char *dev)
39{
40        /* 115200bps, 8 databits, no parity, 1 stopbit */
41        sp_fd = sp_openserport(dev, 115200);
42        return 0;
43}
44#else
45#define buspirate_serialport_setup(...) 0
46#define serialport_shutdown(...) 0
47#define serialport_write(...) 0
48#define serialport_read(...) 0
49#define sp_flush_incoming(...) 0
50#endif
51
52static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt,
53                              unsigned int readcnt)
54{
55        int i, ret = 0;
56
57        msg_pspew("%s: write %i, read %i ", __func__, writecnt, readcnt);
58        if (!writecnt && !readcnt) {
59                msg_perr("Zero length command!\n");
60                return 1;
61        }
62        msg_pspew("Sending");
63        for (i = 0; i < writecnt; i++)
64                msg_pspew(" 0x%02x", buf[i]);
65#ifdef FAKE_COMMUNICATION
66        /* Placate the caller for now. */
67        if (readcnt) {
68                buf[0] = 0x01;
69                memset(buf + 1, 0xff, readcnt - 1);
70        }
71        ret = 0;
72#else
73        if (writecnt)
74                ret = serialport_write(buf, writecnt);
75        if (ret)
76                return ret;
77        if (readcnt)
78                ret = serialport_read(buf, readcnt);
79        if (ret)
80                return ret;
81#endif
82        msg_pspew(", receiving");
83        for (i = 0; i < readcnt; i++)
84                msg_pspew(" 0x%02x", buf[i]);
85        msg_pspew("\n");
86        return 0;
87}
88
89static int buspirate_spi_send_command(struct flashctx *flash,
90                                      unsigned int writecnt,
91                                      unsigned int readcnt,
92                                      const unsigned char *writearr,
93                                      unsigned char *readarr);
94
95static const struct spi_programmer spi_programmer_buspirate = {
96        .type           = SPI_CONTROLLER_BUSPIRATE,
97        .max_data_read  = 12,
98        .max_data_write = 12,
99        .command        = buspirate_spi_send_command,
100        .multicommand   = default_spi_send_multicommand,
101        .read           = default_spi_read,
102        .write_256      = default_spi_write_256,
103};
104
105static const struct buspirate_spispeeds spispeeds[] = {
106        {"30k",         0x0},
107        {"125k",        0x1},
108        {"250k",        0x2},
109        {"1M",          0x3},
110        {"2M",          0x4},
111        {"2.6M",        0x5},
112        {"4M",          0x6},
113        {"8M",          0x7},
114        {NULL,          0x0},
115};
116
117static int buspirate_spi_shutdown(void *data)
118{
119        unsigned char buf[5];
120        int ret = 0;
121
122        /* Exit raw SPI mode (enter raw bitbang mode) */
123        buf[0] = 0x00;
124        ret = buspirate_sendrecv(buf, 1, 5);
125        if (ret)
126                return ret;
127        if (memcmp(buf, "BBIO", 4)) {
128                msg_perr("Entering raw bitbang mode failed!\n");
129                return 1;
130        }
131        msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
132        if (buf[4] != '1') {
133                msg_perr("Can't handle raw bitbang mode version %c!\n",
134                        buf[4]);
135                return 1;
136        }
137        /* Reset Bus Pirate (return to user terminal) */
138        buf[0] = 0x0f;
139        ret = buspirate_sendrecv(buf, 1, 0);
140        if (ret)
141                return ret;
142
143        /* Shut down serial port communication */
144        ret = serialport_shutdown(NULL);
145        if (ret)
146                return ret;
147        msg_pdbg("Bus Pirate shutdown completed.\n");
148
149        return 0;
150}
151
152int buspirate_spi_init(void)
153{
154        unsigned char buf[512];
155        char *dev = NULL;
156        char *speed = NULL;
157        int spispeed = 0x7;
158        int ret = 0;
159        int i;
160
161        dev = extract_programmer_param("dev");
162        if (!dev || !strlen(dev)) {
163                msg_perr("No serial device given. Use flashrom -p "
164                        "buspirate_spi:dev=/dev/ttyUSB0\n");
165                return 1;
166        }
167
168        speed = extract_programmer_param("spispeed");
169        if (speed) {
170                for (i = 0; spispeeds[i].name; i++)
171                        if (!strncasecmp(spispeeds[i].name, speed,
172                            strlen(spispeeds[i].name))) {
173                                spispeed = spispeeds[i].speed;
174                                break;
175                        }
176                if (!spispeeds[i].name)
177                        msg_perr("Invalid SPI speed, using default.\n");
178        }
179        free(speed);
180
181        /* This works because speeds numbering starts at 0 and is contiguous. */
182        msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
183
184        ret = buspirate_serialport_setup(dev);
185        if (ret)
186                return ret;
187        free(dev);
188
189        if (register_shutdown(buspirate_spi_shutdown, NULL))
190                return 1;
191
192        /* This is the brute force version, but it should work. */
193        for (i = 0; i < 19; i++) {
194                /* Enter raw bitbang mode */
195                buf[0] = 0x00;
196                /* Send the command, don't read the response. */
197                ret = buspirate_sendrecv(buf, 1, 0);
198                if (ret)
199                        return ret;
200                /* Read any response and discard it. */
201                sp_flush_incoming();
202        }
203        /* USB is slow. The Bus Pirate is even slower. Apparently the flush
204         * action above is too fast or too early. Some stuff still remains in
205         * the pipe after the flush above, and one additional flush is not
206         * sufficient either. Use a 1.5 ms delay inside the loop to make
207         * mostly sure that at least one USB frame had time to arrive.
208         * Looping only 5 times is not sufficient and causes the
209         * occasional failure.
210         * Folding the delay into the loop above is not reliable either.
211         */
212        for (i = 0; i < 10; i++) {
213                usleep(1500);
214                /* Read any response and discard it. */
215                sp_flush_incoming();
216        }
217        /* Enter raw bitbang mode */
218        buf[0] = 0x00;
219        ret = buspirate_sendrecv(buf, 1, 5);
220        if (ret)
221                return ret;
222        if (memcmp(buf, "BBIO", 4)) {
223                msg_perr("Entering raw bitbang mode failed!\n");
224                msg_pdbg("Got %02x%02x%02x%02x%02x\n",
225                         buf[0], buf[1], buf[2], buf[3], buf[4]);
226                return 1;
227        }
228        msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
229        if (buf[4] != '1') {
230                msg_perr("Can't handle raw bitbang mode version %c!\n",
231                        buf[4]);
232                return 1;
233        }
234        /* Enter raw SPI mode */
235        buf[0] = 0x01;
236        ret = buspirate_sendrecv(buf, 1, 4);
237        if (ret)
238                return ret;
239        if (memcmp(buf, "SPI", 3)) {
240                msg_perr("Entering raw SPI mode failed!\n");
241                msg_pdbg("Got %02x%02x%02x%02x\n",
242                         buf[0], buf[1], buf[2], buf[3]);
243                return 1;
244        }
245        msg_pdbg("Raw SPI mode version %c\n", buf[3]);
246        if (buf[3] != '1') {
247                msg_perr("Can't handle raw SPI mode version %c!\n",
248                        buf[3]);
249                return 1;
250        }
251
252        /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
253        buf[0] = 0x40 | 0xb;
254        ret = buspirate_sendrecv(buf, 1, 1);
255        if (ret)
256                return 1;
257        if (buf[0] != 0x01) {
258                msg_perr("Protocol error while setting power/CS/AUX!\n");
259                return 1;
260        }
261
262        /* Set SPI speed */
263        buf[0] = 0x60 | spispeed;
264        ret = buspirate_sendrecv(buf, 1, 1);
265        if (ret)
266                return 1;
267        if (buf[0] != 0x01) {
268                msg_perr("Protocol error while setting SPI speed!\n");
269                return 1;
270        }
271       
272        /* Set SPI config: output type, idle, clock edge, sample */
273        buf[0] = 0x80 | 0xa;
274        ret = buspirate_sendrecv(buf, 1, 1);
275        if (ret)
276                return 1;
277        if (buf[0] != 0x01) {
278                msg_perr("Protocol error while setting SPI config!\n");
279                return 1;
280        }
281
282        /* De-assert CS# */
283        buf[0] = 0x03;
284        ret = buspirate_sendrecv(buf, 1, 1);
285        if (ret)
286                return 1;
287        if (buf[0] != 0x01) {
288                msg_perr("Protocol error while raising CS#!\n");
289                return 1;
290        }
291
292        register_spi_programmer(&spi_programmer_buspirate);
293
294        return 0;
295}
296
297static int buspirate_spi_send_command(struct flashctx *flash,
298                                      unsigned int writecnt,
299                                      unsigned int readcnt,
300                                      const unsigned char *writearr,
301                                      unsigned char *readarr)
302{
303        static unsigned char *buf = NULL;
304        unsigned int i = 0;
305        int ret = 0;
306
307        if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
308                return SPI_INVALID_LENGTH;
309
310        /* 3 bytes extra for CS#, len, CS#. */
311        buf = realloc(buf, writecnt + readcnt + 3);
312        if (!buf) {
313                msg_perr("Out of memory!\n");
314                exit(1); // -1
315        }
316
317        /* Assert CS# */
318        buf[i++] = 0x02;
319
320        buf[i++] = 0x10 | (writecnt + readcnt - 1);
321        memcpy(buf + i, writearr, writecnt);
322        i += writecnt;
323        memset(buf + i, 0, readcnt);
324
325        i += readcnt;
326        /* De-assert CS# */
327        buf[i++] = 0x03;
328
329        ret = buspirate_sendrecv(buf, i, i);
330
331        if (ret) {
332                msg_perr("Bus Pirate communication error!\n");
333                return SPI_GENERIC_ERROR;
334        }
335
336        if (buf[0] != 0x01) {
337                msg_perr("Protocol error while lowering CS#!\n");
338                return SPI_GENERIC_ERROR;
339        }
340
341        if (buf[1] != 0x01) {
342                msg_perr("Protocol error while reading/writing SPI!\n");
343                return SPI_GENERIC_ERROR;
344        }
345
346        if (buf[i - 1] != 0x01) {
347                msg_perr("Protocol error while raising CS#!\n");
348                return SPI_GENERIC_ERROR;
349        }
350
351        /* Skip CS#, length, writearr. */
352        memcpy(readarr, buf + 2 + writecnt, readcnt);
353
354        return ret;
355}
Note: See TracBrowser for help on using the repository browser.