source: trunk/ft2232_spi.c @ 1537

Revision 1537, 12.9 KB checked in by stefanct, 5 days ago (diff)

ft2232_spi.c: add frequency divisor parameter.

This adds an optional argument when using the ft2232_spi programmer to set
the frequency divisor. The valid values for the divisor is any even integer
between 2 and 131072.

Signed-off-by: Samir Ibradžić <sibradzic@…>
Signed-off-by: Stefan Tauner <stefan.tauner@…>
Acked-by: Stefan Tauner <stefan.tauner@…>

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