source: trunk/ft2232_spi.c

Last change on this file was 1632, checked in by stefanct, 6 months ago

Unify usbdev_status and pcidev_status into dev_entry.

Once upon a time usbdev_status was created for the ft2232
programmer. Its IDs are semantically different to pcidev_status
because they indicate USB instead of PCI IDs, but apart from that
both data structures are equal. This change makes life easier for
everything involved in handling and printing the status of devices
that is noted in those structures by combining them into dev_entry.

It is still possible to distinguish between PCI and USB devices
indirectly by using the struct programmer's type field.

Also, add a programmer column to the PCI and USB devices lists.

Signed-off-by: Stefan Tauner <stefan.tauner@…>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>

File size: 13.6 KB
Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
5 * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19 */
20
21#if CONFIG_FT2232_SPI == 1
22
23#include <stdio.h>
24#include <strings.h>
25#include <string.h>
26#include <stdlib.h>
27#include <ctype.h>
28#include "flash.h"
29#include "programmer.h"
30#include "spi.h"
31#include <ftdi.h>
32
33/* This is not defined in libftdi.h <0.20 (c7e4c09e68cfa6f5e112334aa1b3bb23401c8dc7 to be exact).
34 * Some tests indicate that his is the only change that it is needed to support the FT232H in flashrom. */
35#if !defined(HAVE_FT232H)
36#define TYPE_232H       6
37#endif
38
39/* Please keep sorted by vendor ID, then device ID. */
40
41#define FTDI_VID                0x0403
42#define FTDI_FT2232H_PID        0x6010
43#define FTDI_FT4232H_PID        0x6011
44#define FTDI_FT232H_PID         0x6014
45#define TIAO_TUMPA_PID          0x8a98
46#define AMONTEC_JTAGKEY_PID     0xCFF8
47
48#define GOEPEL_VID              0x096C
49#define GOEPEL_PICOTAP_PID      0x1449
50
51#define FIC_VID                 0x1457
52#define OPENMOKO_DBGBOARD_PID   0x5118
53
54#define OLIMEX_VID              0x15BA
55#define OLIMEX_ARM_OCD_PID      0x0003
56#define OLIMEX_ARM_TINY_PID     0x0004
57#define OLIMEX_ARM_OCD_H_PID    0x002B
58#define OLIMEX_ARM_TINY_H_PID   0x002A
59
60const struct dev_entry devs_ft2232spi[] = {
61        {FTDI_VID, FTDI_FT2232H_PID, OK, "FTDI", "FT2232H"},
62        {FTDI_VID, FTDI_FT4232H_PID, OK, "FTDI", "FT4232H"},
63        {FTDI_VID, FTDI_FT232H_PID, OK, "FTDI", "FT232H"},
64        {FTDI_VID, TIAO_TUMPA_PID, OK, "TIAO", "USB Multi-Protocol Adapter"},
65        {FTDI_VID, AMONTEC_JTAGKEY_PID, OK, "Amontec", "JTAGkey"},
66        {GOEPEL_VID, GOEPEL_PICOTAP_PID, OK, "GOEPEL", "PicoTAP"},
67        {FIC_VID, OPENMOKO_DBGBOARD_PID, OK, "FIC", "OpenMoko Neo1973 Debug board (V2+)"},
68        {OLIMEX_VID, OLIMEX_ARM_OCD_PID, NT, "Olimex", "ARM-USB-OCD"},
69        {OLIMEX_VID, OLIMEX_ARM_TINY_PID, OK, "Olimex", "ARM-USB-TINY"},
70        {OLIMEX_VID, OLIMEX_ARM_OCD_H_PID, NT, "Olimex", "ARM-USB-OCD-H"},
71        {OLIMEX_VID, OLIMEX_ARM_TINY_H_PID, NT, "Olimex", "ARM-USB-TINY-H"},
72
73        {0},
74};
75
76#define DEFAULT_DIVISOR 2
77
78#define BITMODE_BITBANG_NORMAL  1
79#define BITMODE_BITBANG_SPI     2
80
81/* Set data bits low-byte command:
82 *  value: 0x08  CS=high, DI=low, DO=low, SK=low
83 *    dir: 0x0b  CS=output, DI=input, DO=output, SK=output
84 *
85 * JTAGkey(2) needs to enable its output via Bit4 / GPIOL0
86 *  value: 0x18  OE=high, CS=high, DI=low, DO=low, SK=low
87 *    dir: 0x1b  OE=output, CS=output, DI=input, DO=output, SK=output
88 */
89static uint8_t cs_bits = 0x08;
90static uint8_t pindir = 0x0b;
91static struct ftdi_context ftdic_context;
92
93static const char *get_ft2232_devicename(int ft2232_vid, int ft2232_type)
94{
95        int i;
96        for (i = 0; devs_ft2232spi[i].vendor_name != NULL; i++) {
97                if ((devs_ft2232spi[i].device_id == ft2232_type) && (devs_ft2232spi[i].vendor_id == ft2232_vid))
98                                return devs_ft2232spi[i].device_name;
99        }
100        return "unknown device";
101}
102
103static const char *get_ft2232_vendorname(int ft2232_vid, int ft2232_type)
104{
105        int i;
106        for (i = 0; devs_ft2232spi[i].vendor_name != NULL; i++) {
107                if ((devs_ft2232spi[i].device_id == ft2232_type) && (devs_ft2232spi[i].vendor_id == ft2232_vid))
108                                return devs_ft2232spi[i].vendor_name;
109        }
110        return "unknown vendor";
111}
112
113static int send_buf(struct ftdi_context *ftdic, const unsigned char *buf,
114                    int size)
115{
116        int r;
117        r = ftdi_write_data(ftdic, (unsigned char *) buf, size);
118        if (r < 0) {
119                msg_perr("ftdi_write_data: %d, %s\n", r, ftdi_get_error_string(ftdic));
120                return 1;
121        }
122        return 0;
123}
124
125static int get_buf(struct ftdi_context *ftdic, const unsigned char *buf,
126                   int size)
127{
128        int r;
129
130        while (size > 0) {
131                r = ftdi_read_data(ftdic, (unsigned char *) buf, size);
132                if (r < 0) {
133                        msg_perr("ftdi_read_data: %d, %s\n", r, ftdi_get_error_string(ftdic));
134                        return 1;
135                }
136                buf += r;
137                size -= r;
138        }
139        return 0;
140}
141
142static int ft2232_spi_send_command(struct flashctx *flash,
143                                   unsigned int writecnt, unsigned int readcnt,
144                                   const unsigned char *writearr,
145                                   unsigned char *readarr);
146
147static const struct spi_programmer spi_programmer_ft2232 = {
148        .type           = SPI_CONTROLLER_FT2232,
149        .max_data_read  = 64 * 1024,
150        .max_data_write = 256,
151        .command        = ft2232_spi_send_command,
152        .multicommand   = default_spi_send_multicommand,
153        .read           = default_spi_read,
154        .write_256      = default_spi_write_256,
155        .write_aai      = default_spi_write_aai,
156};
157
158/* Returns 0 upon success, a negative number upon errors. */
159int ft2232_spi_init(void)
160{
161        int ret = 0;
162        struct ftdi_context *ftdic = &ftdic_context;
163        unsigned char buf[512];
164        int ft2232_vid = FTDI_VID;
165        int ft2232_type = FTDI_FT4232H_PID;
166        int channel_count = 4; /* Stores the number of channels of the device. */
167        enum ftdi_interface ft2232_interface = INTERFACE_A;
168        /*
169         * The 'H' chips can run with an internal clock of either 12 MHz or 60 MHz,
170         * but the non-H chips can only run at 12 MHz. We enable the divide-by-5
171         * prescaler on the former to run on the same speed.
172         */
173        uint8_t clock_5x = 1;
174        /* In addition to the prescaler mentioned above there is also another
175         * configurable one on all versions of the chips. Its divisor div can be
176         * set by a 16 bit value x according to the following formula:
177         * div = (1 + x) * 2 <-> x = div / 2 - 1
178         * Hence the expressible divisors are all even numbers between 2 and
179         * 2^17 (=131072) resulting in SCK frequencies of 6 MHz down to about
180         * 92 Hz for 12 MHz inputs.
181         */
182        uint32_t divisor = DEFAULT_DIVISOR;
183        int f;
184        char *arg;
185        double mpsse_clk;
186
187        arg = extract_programmer_param("type");
188        if (arg) {
189                if (!strcasecmp(arg, "2232H")) {
190                        ft2232_type = FTDI_FT2232H_PID;
191                        channel_count = 2;
192                } else if (!strcasecmp(arg, "4232H")) {
193                        ft2232_type = FTDI_FT4232H_PID;
194                        channel_count = 4;
195                } else if (!strcasecmp(arg, "232H")) {
196                        ft2232_type = FTDI_FT232H_PID;
197                        channel_count = 1;
198                } else if (!strcasecmp(arg, "jtagkey")) {
199                        ft2232_type = AMONTEC_JTAGKEY_PID;
200                        channel_count = 2;
201                        cs_bits = 0x18;
202                        pindir = 0x1b;
203                } else if (!strcasecmp(arg, "picotap")) {
204                        ft2232_vid = GOEPEL_VID;
205                        ft2232_type = GOEPEL_PICOTAP_PID;
206                        channel_count = 2;
207                } else if (!strcasecmp(arg, "tumpa")) {
208                        /* Interface A is SPI1, B is SPI2. */
209                        ft2232_type = TIAO_TUMPA_PID;
210                        channel_count = 2;
211                } else if (!strcasecmp(arg, "busblaster")) {
212                        /* In its default configuration it is a jtagkey clone */
213                        ft2232_type = FTDI_FT2232H_PID;
214                        channel_count = 2;
215                        cs_bits = 0x18;
216                        pindir = 0x1b;
217                } else if (!strcasecmp(arg, "openmoko")) {
218                        ft2232_vid = FIC_VID;
219                        ft2232_type = OPENMOKO_DBGBOARD_PID;
220                        channel_count = 2;
221                } else if (!strcasecmp(arg, "arm-usb-ocd")) {
222                        ft2232_vid = OLIMEX_VID;
223                        ft2232_type = OLIMEX_ARM_OCD_PID;
224                        channel_count = 2;
225                        cs_bits = 0x08;
226                        pindir = 0x1b;
227                } else if (!strcasecmp(arg, "arm-usb-tiny")) {
228                        ft2232_vid = OLIMEX_VID;
229                        ft2232_type = OLIMEX_ARM_TINY_PID;
230                        channel_count = 2;
231                } else if (!strcasecmp(arg, "arm-usb-ocd-h")) {
232                        ft2232_vid = OLIMEX_VID;
233                        ft2232_type = OLIMEX_ARM_OCD_H_PID;
234                        channel_count = 2;
235                        cs_bits = 0x08;
236                        pindir = 0x1b;
237                } else if (!strcasecmp(arg, "arm-usb-tiny-h")) {
238                        ft2232_vid = OLIMEX_VID;
239                        ft2232_type = OLIMEX_ARM_TINY_H_PID;
240                        channel_count = 2;
241                } else {
242                        msg_perr("Error: Invalid device type specified.\n");
243                        free(arg);
244                        return -1;
245                }
246        }
247        free(arg);
248
249        arg = extract_programmer_param("port");
250        if (arg) {
251                switch (toupper((unsigned char)*arg)) {
252                case 'A':
253                        ft2232_interface = INTERFACE_A;
254                        break;
255                case 'B':
256                        ft2232_interface = INTERFACE_B;
257                        if (channel_count < 2)
258                                channel_count = -1;
259                        break;
260                case 'C':
261                        ft2232_interface = INTERFACE_C;
262                        if (channel_count < 3)
263                                channel_count = -1;
264                        break;
265                case 'D':
266                        ft2232_interface = INTERFACE_D;
267                        if (channel_count < 4)
268                                channel_count = -1;
269                        break;
270                default:
271                        channel_count = -1;
272                        break;
273                }
274                if (channel_count < 0 || strlen(arg) != 1) {
275                        msg_perr("Error: Invalid channel/port/interface specified: \"%s\".\n", arg);
276                        free(arg);
277                        return -2;
278                }
279        }
280        free(arg);
281
282        arg = extract_programmer_param("divisor");
283        if (arg && strlen(arg)) {
284                unsigned int temp = 0;
285                char *endptr;
286                temp = strtoul(arg, &endptr, 10);
287                if (*endptr || temp < 2 || temp > 131072 || temp & 0x1) {
288                        msg_perr("Error: Invalid SPI frequency divisor specified: \"%s\".\n"
289                                 "Valid are even values between 2 and 131072.\n", arg);
290                        free(arg);
291                        return -2;
292                } else {
293                        divisor = (uint32_t)temp;
294                }
295        }
296        free(arg);
297
298        msg_pdbg("Using device type %s %s ",
299                 get_ft2232_vendorname(ft2232_vid, ft2232_type),
300                 get_ft2232_devicename(ft2232_vid, ft2232_type));
301        msg_pdbg("channel %s.\n",
302                 (ft2232_interface == INTERFACE_A) ? "A" :
303                 (ft2232_interface == INTERFACE_B) ? "B" :
304                 (ft2232_interface == INTERFACE_C) ? "C" : "D");
305
306        if (ftdi_init(ftdic) < 0) {
307                msg_perr("ftdi_init failed.\n");
308                return -3;
309        }
310
311        if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
312                msg_perr("Unable to select channel (%s).\n", ftdi_get_error_string(ftdic));
313        }
314
315        arg = extract_programmer_param("serial");
316        f = ftdi_usb_open_desc(ftdic, ft2232_vid, ft2232_type, NULL, arg);
317        free(arg);
318
319        if (f < 0 && f != -5) {
320                msg_perr("Unable to open FTDI device: %d (%s).\n", f, ftdi_get_error_string(ftdic));
321                return -4;
322        }
323
324        if (ftdic->type != TYPE_2232H && ftdic->type != TYPE_4232H && ftdic->type != TYPE_232H) {
325                msg_pdbg("FTDI chip type %d is not high-speed.\n", ftdic->type);
326                clock_5x = 0;
327        }
328
329        if (ftdi_usb_reset(ftdic) < 0) {
330                msg_perr("Unable to reset FTDI device (%s).\n", ftdi_get_error_string(ftdic));
331        }
332
333        if (ftdi_set_latency_timer(ftdic, 2) < 0) {
334                msg_perr("Unable to set latency timer (%s).\n", ftdi_get_error_string(ftdic));
335        }
336
337        if (ftdi_write_data_set_chunksize(ftdic, 256)) {
338                msg_perr("Unable to set chunk size (%s).\n", ftdi_get_error_string(ftdic));
339        }
340
341        if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
342                msg_perr("Unable to set bitmode to SPI (%s).\n", ftdi_get_error_string(ftdic));
343        }
344
345        if (clock_5x) {
346                msg_pdbg("Disable divide-by-5 front stage\n");
347                buf[0] = 0x8a;          /* Disable divide-by-5. */
348                if (send_buf(ftdic, buf, 1)) {
349                        ret = -5;
350                        goto ftdi_err;
351                }
352                mpsse_clk = 60.0;
353        } else {
354                mpsse_clk = 12.0;
355        }
356
357        msg_pdbg("Set clock divisor\n");
358        buf[0] = 0x86;          /* command "set divisor" */
359        buf[1] = (divisor / 2 - 1) & 0xff;
360        buf[2] = ((divisor / 2 - 1) >> 8) & 0xff;
361        if (send_buf(ftdic, buf, 3)) {
362                ret = -6;
363                goto ftdi_err;
364        }
365
366        msg_pdbg("MPSSE clock: %f MHz, divisor: %u, SPI clock: %f MHz\n",
367                 mpsse_clk, divisor, (double)(mpsse_clk / divisor));
368
369        /* Disconnect TDI/DO to TDO/DI for loopback. */
370        msg_pdbg("No loopback of TDI/DO TDO/DI\n");
371        buf[0] = 0x85;
372        if (send_buf(ftdic, buf, 1)) {
373                ret = -7;
374                goto ftdi_err;
375        }
376
377        msg_pdbg("Set data bits\n");
378        buf[0] = SET_BITS_LOW;
379        buf[1] = cs_bits;
380        buf[2] = pindir;
381        if (send_buf(ftdic, buf, 3)) {
382                ret = -8;
383                goto ftdi_err;
384        }
385
386        register_spi_programmer(&spi_programmer_ft2232);
387
388        return 0;
389
390ftdi_err:
391        if ((f = ftdi_usb_close(ftdic)) < 0) {
392                msg_perr("Unable to close FTDI device: %d (%s)\n", f, ftdi_get_error_string(ftdic));
393        }
394        return ret;
395}
396
397/* Returns 0 upon success, a negative number upon errors. */
398static int ft2232_spi_send_command(struct flashctx *flash,
399                                   unsigned int writecnt, unsigned int readcnt,
400                                   const unsigned char *writearr,
401                                   unsigned char *readarr)
402{
403        struct ftdi_context *ftdic = &ftdic_context;
404        static unsigned char *buf = NULL;
405        /* failed is special. We use bitwise ops, but it is essentially bool. */
406        int i = 0, ret = 0, failed = 0;
407        int bufsize;
408        static int oldbufsize = 0;
409
410        if (writecnt > 65536 || readcnt > 65536)
411                return SPI_INVALID_LENGTH;
412
413        /* buf is not used for the response from the chip. */
414        bufsize = max(writecnt + 9, 260 + 9);
415        /* Never shrink. realloc() calls are expensive. */
416        if (bufsize > oldbufsize) {
417                buf = realloc(buf, bufsize);
418                if (!buf) {
419                        msg_perr("Out of memory!\n");
420                        /* TODO: What to do with buf? */
421                        return SPI_GENERIC_ERROR;
422                }
423                oldbufsize = bufsize;
424        }
425
426        /*
427         * Minimize USB transfers by packing as many commands as possible
428         * together. If we're not expecting to read, we can assert CS#, write,
429         * and deassert CS# all in one shot. If reading, we do three separate
430         * operations.
431         */
432        msg_pspew("Assert CS#\n");
433        buf[i++] = SET_BITS_LOW;
434        buf[i++] = 0 & ~cs_bits; /* assertive */
435        buf[i++] = pindir;
436
437        if (writecnt) {
438                buf[i++] = 0x11;
439                buf[i++] = (writecnt - 1) & 0xff;
440                buf[i++] = ((writecnt - 1) >> 8) & 0xff;
441                memcpy(buf + i, writearr, writecnt);
442                i += writecnt;
443        }
444
445        /*
446         * Optionally terminate this batch of commands with a
447         * read command, then do the fetch of the results.
448         */
449        if (readcnt) {
450                buf[i++] = 0x20;
451                buf[i++] = (readcnt - 1) & 0xff;
452                buf[i++] = ((readcnt - 1) >> 8) & 0xff;
453                ret = send_buf(ftdic, buf, i);
454                failed = ret;
455                /* We can't abort here, we still have to deassert CS#. */
456                if (ret)
457                        msg_perr("send_buf failed before read: %i\n", ret);
458                i = 0;
459                if (ret == 0) {
460                        /*
461                         * FIXME: This is unreliable. There's no guarantee that
462                         * we read the response directly after sending the read
463                         * command. We may be scheduled out etc.
464                         */
465                        ret = get_buf(ftdic, readarr, readcnt);
466                        failed |= ret;
467                        /* We can't abort here either. */
468                        if (ret)
469                                msg_perr("get_buf failed: %i\n", ret);
470                }
471        }
472
473        msg_pspew("De-assert CS#\n");
474        buf[i++] = SET_BITS_LOW;
475        buf[i++] = cs_bits;
476        buf[i++] = pindir;
477        ret = send_buf(ftdic, buf, i);
478        failed |= ret;
479        if (ret)
480                msg_perr("send_buf failed at end: %i\n", ret);
481
482        return failed ? -1 : 0;
483}
484
485#endif
Note: See TracBrowser for help on using the repository browser.