blob: 1106a0ebf87c3d57ea7fa883b711f4b67b273bfc [file] [log] [blame]
Paul Fox05dfbe62009-06-16 21:08:06 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +00005 * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
Paul Fox05dfbe62009-06-16 21:08:06 +00006 *
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.
Paul Fox05dfbe62009-06-16 21:08:06 +000015 */
16
Carl-Daniel Hailfinger71127722010-05-31 15:27:27 +000017#if CONFIG_FT2232_SPI == 1
Carl-Daniel Hailfinger3426ef62009-08-19 13:27:58 +000018
Paul Fox05dfbe62009-06-16 21:08:06 +000019#include <stdio.h>
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +000020#include <strings.h>
Paul Fox05dfbe62009-06-16 21:08:06 +000021#include <string.h>
22#include <stdlib.h>
Carl-Daniel Hailfingerfeea2722009-07-01 00:02:23 +000023#include <ctype.h>
Paul Fox05dfbe62009-06-16 21:08:06 +000024#include "flash.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000025#include "programmer.h"
Paul Fox05dfbe62009-06-16 21:08:06 +000026#include "spi.h"
Paul Fox05dfbe62009-06-16 21:08:06 +000027#include <ftdi.h>
28
Ilya A. Volynets-Evenbakh2c714ab2012-09-26 00:47:09 +000029/* This is not defined in libftdi.h <0.20 (c7e4c09e68cfa6f5e112334aa1b3bb23401c8dc7 to be exact).
Angel Pons44cfbb02021-04-17 17:07:34 +020030 * Some tests indicate that this is the only change that it is needed to support the FT232H in flashrom. */
Ilya A. Volynets-Evenbakh2c714ab2012-09-26 00:47:09 +000031#if !defined(HAVE_FT232H)
32#define TYPE_232H 6
33#endif
34
Uwe Hermann836b26a2011-10-14 20:33:14 +000035/* Please keep sorted by vendor ID, then device ID. */
36
Uwe Hermann70145292010-07-29 19:57:55 +000037#define FTDI_VID 0x0403
38#define FTDI_FT2232H_PID 0x6010
39#define FTDI_FT4232H_PID 0x6011
Ilya A. Volynets-Evenbakh2c714ab2012-09-26 00:47:09 +000040#define FTDI_FT232H_PID 0x6014
Uwe Hermann836b26a2011-10-14 20:33:14 +000041#define TIAO_TUMPA_PID 0x8a98
Stefan Taunerb66ed842014-04-27 05:07:35 +000042#define TIAO_TUMPA_LITE_PID 0x8a99
Uwe Hermann70145292010-07-29 19:57:55 +000043#define AMONTEC_JTAGKEY_PID 0xCFF8
Jörg Fischer6529b9f2010-07-29 15:54:53 +000044
Samir Ibradžić7189a5f2011-10-20 23:14:10 +000045#define GOEPEL_VID 0x096C
46#define GOEPEL_PICOTAP_PID 0x1449
47
Alex Badeacaf2d422010-11-10 03:26:57 +000048#define FIC_VID 0x1457
49#define OPENMOKO_DBGBOARD_PID 0x5118
50
Pete Batardc0207062011-06-11 12:21:37 +000051#define OLIMEX_VID 0x15BA
52#define OLIMEX_ARM_OCD_PID 0x0003
53#define OLIMEX_ARM_TINY_PID 0x0004
54#define OLIMEX_ARM_OCD_H_PID 0x002B
55#define OLIMEX_ARM_TINY_H_PID 0x002A
56
Todd Broch6800c952016-02-14 15:46:00 +000057#define GOOGLE_VID 0x18D1
58#define GOOGLE_SERVO_PID 0x5001
59#define GOOGLE_SERVO_V2_PID0 0x5002
60#define GOOGLE_SERVO_V2_PID1 0x5003
61
Thomas Heijligencc853d82021-05-04 15:32:17 +020062static const struct dev_entry devs_ft2232spi[] = {
Uwe Hermann70145292010-07-29 19:57:55 +000063 {FTDI_VID, FTDI_FT2232H_PID, OK, "FTDI", "FT2232H"},
64 {FTDI_VID, FTDI_FT4232H_PID, OK, "FTDI", "FT4232H"},
Ilya A. Volynets-Evenbakh2c714ab2012-09-26 00:47:09 +000065 {FTDI_VID, FTDI_FT232H_PID, OK, "FTDI", "FT232H"},
Uwe Hermann836b26a2011-10-14 20:33:14 +000066 {FTDI_VID, TIAO_TUMPA_PID, OK, "TIAO", "USB Multi-Protocol Adapter"},
Stefan Taunerb66ed842014-04-27 05:07:35 +000067 {FTDI_VID, TIAO_TUMPA_LITE_PID, OK, "TIAO", "USB Multi-Protocol Adapter Lite"},
Uwe Hermann70145292010-07-29 19:57:55 +000068 {FTDI_VID, AMONTEC_JTAGKEY_PID, OK, "Amontec", "JTAGkey"},
Samir Ibradžić7189a5f2011-10-20 23:14:10 +000069 {GOEPEL_VID, GOEPEL_PICOTAP_PID, OK, "GOEPEL", "PicoTAP"},
Todd Broch6800c952016-02-14 15:46:00 +000070 {GOOGLE_VID, GOOGLE_SERVO_PID, OK, "Google", "Servo"},
71 {GOOGLE_VID, GOOGLE_SERVO_V2_PID0, OK, "Google", "Servo V2 Legacy"},
72 {GOOGLE_VID, GOOGLE_SERVO_V2_PID1, OK, "Google", "Servo V2"},
Stefan Tauner3e515e22012-09-26 00:48:16 +000073 {FIC_VID, OPENMOKO_DBGBOARD_PID, OK, "FIC", "OpenMoko Neo1973 Debug board (V2+)"},
Stefan Tauner74dc73f2015-03-01 22:04:38 +000074 {OLIMEX_VID, OLIMEX_ARM_OCD_PID, OK, "Olimex", "ARM-USB-OCD"},
Pete Batardc0207062011-06-11 12:21:37 +000075 {OLIMEX_VID, OLIMEX_ARM_TINY_PID, OK, "Olimex", "ARM-USB-TINY"},
Stefan Tauner6697f712014-08-06 15:09:15 +000076 {OLIMEX_VID, OLIMEX_ARM_OCD_H_PID, OK, "Olimex", "ARM-USB-OCD-H"},
Stefan Taunerc2eec2c2014-05-03 21:33:01 +000077 {OLIMEX_VID, OLIMEX_ARM_TINY_H_PID, OK, "Olimex", "ARM-USB-TINY-H"},
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +000078
79 {0},
Jörg Fischer6529b9f2010-07-29 15:54:53 +000080};
81
Simon Buhrowdb9be312021-04-09 14:48:39 +020082#define FTDI_HW_BUFFER_SIZE 4096 /* in bytes */
83
Samir Ibradžićb482c6d2012-05-15 22:58:19 +000084#define DEFAULT_DIVISOR 2
Paul Fox05dfbe62009-06-16 21:08:06 +000085
Uwe Hermannc67d0372009-10-01 18:40:02 +000086#define BITMODE_BITBANG_NORMAL 1
87#define BITMODE_BITBANG_SPI 2
Paul Fox05dfbe62009-06-16 21:08:06 +000088
Nico Hubercf880682021-06-20 15:59:57 +020089/*
90 * The variables `cs_bits` and `pindir` store the values for the
91 * "set data bits low byte" MPSSE command that sets the initial
92 * state and the direction of the I/O pins. `cs_bits` pins default
93 * to high and will be toggled during SPI transactions. All other
Michael Niewöhnerc2b303b2021-09-21 18:03:29 +020094 * output pins will be kept low all the time. For some programmers,
95 * some reserved GPIOL* pins are used as outputs. Free GPIOL* pins
Michael Niewöhnerece63c82021-09-21 20:15:32 +020096 * are configured as inputs, while it's possible to use them either
97 * as generic gpios or as additional CS# signal(s) through the
98 * parameter(s) `gpiolX`. On exit, all pins will be reconfigured
99 * as inputs.
Antony Pavlovb4dd40c2015-01-25 03:52:47 +0000100 *
Nico Hubercf880682021-06-20 15:59:57 +0200101 * The pin offsets are as follows:
102 * TCK/SK is bit 0.
103 * TDI/DO is bit 1.
104 * TDO/DI is bit 2.
105 * TMS/CS is bit 3.
106 * GPIOL0 is bit 4.
107 * GPIOL1 is bit 5.
108 * GPIOL2 is bit 6.
109 * GPIOL3 is bit 7.
110 *
111 * The default values (set below in ft2232_spi_init) are used for
112 * most devices:
113 * value: 0x08 CS=high, DI=low, DO=low, SK=low
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000114 * dir: 0x0b CS=output, DI=input, DO=output, SK=output
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000115 */
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000116struct ft2232_data {
117 uint8_t cs_bits;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200118 uint8_t aux_bits;
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000119 uint8_t pindir;
120 struct ftdi_context ftdi_context;
121};
Paul Fox05dfbe62009-06-16 21:08:06 +0000122
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000123static const char *get_ft2232_devicename(int ft2232_vid, int ft2232_type)
124{
125 int i;
Uwe Hermann70145292010-07-29 19:57:55 +0000126 for (i = 0; devs_ft2232spi[i].vendor_name != NULL; i++) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000127 if ((devs_ft2232spi[i].device_id == ft2232_type) && (devs_ft2232spi[i].vendor_id == ft2232_vid))
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000128 return devs_ft2232spi[i].device_name;
129 }
130 return "unknown device";
131}
132
133static const char *get_ft2232_vendorname(int ft2232_vid, int ft2232_type)
134{
135 int i;
Uwe Hermann70145292010-07-29 19:57:55 +0000136 for (i = 0; devs_ft2232spi[i].vendor_name != NULL; i++) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000137 if ((devs_ft2232spi[i].device_id == ft2232_type) && (devs_ft2232spi[i].vendor_id == ft2232_vid))
Uwe Hermann70145292010-07-29 19:57:55 +0000138 return devs_ft2232spi[i].vendor_name;
139 }
140 return "unknown vendor";
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000141}
142
Uwe Hermann70145292010-07-29 19:57:55 +0000143static int send_buf(struct ftdi_context *ftdic, const unsigned char *buf,
144 int size)
Paul Fox05dfbe62009-06-16 21:08:06 +0000145{
146 int r;
147 r = ftdi_write_data(ftdic, (unsigned char *) buf, size);
148 if (r < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000149 msg_perr("ftdi_write_data: %d, %s\n", r, ftdi_get_error_string(ftdic));
Paul Fox05dfbe62009-06-16 21:08:06 +0000150 return 1;
151 }
152 return 0;
153}
154
Uwe Hermann70145292010-07-29 19:57:55 +0000155static int get_buf(struct ftdi_context *ftdic, const unsigned char *buf,
156 int size)
Paul Fox05dfbe62009-06-16 21:08:06 +0000157{
158 int r;
Alex Badeab9556e02010-11-10 03:10:41 +0000159
160 while (size > 0) {
161 r = ftdi_read_data(ftdic, (unsigned char *) buf, size);
162 if (r < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000163 msg_perr("ftdi_read_data: %d, %s\n", r, ftdi_get_error_string(ftdic));
Alex Badeab9556e02010-11-10 03:10:41 +0000164 return 1;
165 }
166 buf += r;
167 size -= r;
Paul Fox05dfbe62009-06-16 21:08:06 +0000168 }
169 return 0;
170}
171
Alan Green460c1c02021-01-08 09:36:45 +1100172static int ft2232_shutdown(void *data)
173{
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000174 struct ft2232_data *spi_data = (struct ft2232_data *)data;
175 struct ftdi_context *ftdic = &spi_data->ftdi_context;
Alan Green460c1c02021-01-08 09:36:45 +1100176 unsigned char buf[3];
Nico Huber4c40a792021-06-20 16:38:57 +0200177 int ret = 0;
Alan Green460c1c02021-01-08 09:36:45 +1100178
179 msg_pdbg("Releasing I/Os\n");
180 buf[0] = SET_BITS_LOW;
181 buf[1] = 0; /* Output byte ignored */
182 buf[2] = 0; /* Pin direction: all inputs */
183 if (send_buf(ftdic, buf, 3)) {
Nico Huberfda5f1f2021-06-20 16:46:31 +0200184 msg_perr("Unable to set pins back to inputs.\n");
Nico Huber4c40a792021-06-20 16:38:57 +0200185 ret = 1;
Alan Green460c1c02021-01-08 09:36:45 +1100186 }
187
Nico Huber4c40a792021-06-20 16:38:57 +0200188 const int close_ret = ftdi_usb_close(ftdic);
189 if (close_ret < 0) {
190 msg_perr("Unable to close FTDI device: %d (%s)\n", close_ret,
Alan Green460c1c02021-01-08 09:36:45 +1100191 ftdi_get_error_string(ftdic));
Nico Huber4c40a792021-06-20 16:38:57 +0200192 ret = 1;
Alan Green460c1c02021-01-08 09:36:45 +1100193 }
194
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000195 free(spi_data);
Nico Huber4c40a792021-06-20 16:38:57 +0200196 return ret;
Alan Green460c1c02021-01-08 09:36:45 +1100197}
198
Simon Buhrowdb9be312021-04-09 14:48:39 +0200199static bool ft2232_spi_command_fits(const struct spi_command *cmd, size_t buffer_size)
200{
201 const size_t cmd_len = 3; /* same length for any ft2232 command */
202 return
203 /* commands for CS# assertion and de-assertion: */
204 cmd_len + cmd_len
205 /* commands for either a write, a read or both: */
206 + (cmd->writecnt && cmd->readcnt ? cmd_len + cmd_len : cmd_len)
207 /* payload (only writecnt; readcnt concerns another buffer): */
208 + cmd->writecnt
209 <= buffer_size;
210}
211
212/* Returns 0 upon success, a negative number upon errors. */
213static int ft2232_spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds)
214{
215 struct ft2232_data *spi_data = flash->mst->spi.data;
216 struct ftdi_context *ftdic = &spi_data->ftdi_context;
217 static unsigned char buf[FTDI_HW_BUFFER_SIZE];
218 size_t i = 0;
219 int ret = 0;
220
221 /*
222 * Minimize FTDI-calls by packing as many commands as possible together.
223 */
224 for (; cmds->writecnt || cmds->readcnt; cmds++) {
225
226 if (cmds->writecnt > 65536 || cmds->readcnt > 65536)
227 return SPI_INVALID_LENGTH;
228
229 if (!ft2232_spi_command_fits(cmds, FTDI_HW_BUFFER_SIZE - i)) {
230 msg_perr("Command does not fit\n");
231 return SPI_GENERIC_ERROR;
232 }
233
234 msg_pspew("Assert CS#\n");
235 buf[i++] = SET_BITS_LOW;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200236 /* assert CS# pins, keep aux_bits, all other output pins stay low */
237 buf[i++] = spi_data->aux_bits;
Simon Buhrowdb9be312021-04-09 14:48:39 +0200238 buf[i++] = spi_data->pindir;
239
240 /* WREN, OP(PROGRAM, ERASE), ADDR, DATA */
241 if (cmds->writecnt) {
242 buf[i++] = MPSSE_DO_WRITE | MPSSE_WRITE_NEG;
243 buf[i++] = (cmds->writecnt - 1) & 0xff;
244 buf[i++] = ((cmds->writecnt - 1) >> 8) & 0xff;
245 memcpy(buf + i, cmds->writearr, cmds->writecnt);
246 i += cmds->writecnt;
247 }
248
249 /* An optional read command */
250 if (cmds->readcnt) {
251 buf[i++] = MPSSE_DO_READ;
252 buf[i++] = (cmds->readcnt - 1) & 0xff;
253 buf[i++] = ((cmds->readcnt - 1) >> 8) & 0xff;
254 }
255
256 /* Add final de-assert CS# */
257 msg_pspew("De-assert CS#\n");
258 buf[i++] = SET_BITS_LOW;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200259 buf[i++] = spi_data->cs_bits | spi_data->aux_bits;
Simon Buhrowdb9be312021-04-09 14:48:39 +0200260 buf[i++] = spi_data->pindir;
261
262 /* continue if there is no read-cmd and further cmds exist */
263 if (!cmds->readcnt &&
264 ((cmds + 1)->writecnt || (cmds + 1)->readcnt) &&
265 ft2232_spi_command_fits((cmds + 1), FTDI_HW_BUFFER_SIZE - i)) {
266 continue;
267 }
268
269 ret = send_buf(ftdic, buf, i);
270 i = 0;
271 if (ret) {
272 msg_perr("send_buf failed: %i\n", ret);
273 break;
274 }
275
276 if (cmds->readcnt) {
277 ret = get_buf(ftdic, cmds->readarr, cmds->readcnt);
278 if (ret) {
279 msg_perr("get_buf failed: %i\n", ret);
280 break;
281 }
282 }
283 }
284 return ret ? -1 : 0;
285}
286
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000287static struct spi_master spi_master_ft2232 = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100288 .features = SPI_MASTER_4BA,
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000289 .max_data_read = 64 * 1024,
290 .max_data_write = 256,
Nico Huber13b33bc2021-06-20 13:20:33 +0200291 .command = default_spi_send_command,
Simon Buhrowdb9be312021-04-09 14:48:39 +0200292 .multicommand = ft2232_spi_send_multicommand,
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000293 .read = default_spi_read,
294 .write_256 = default_spi_write_256,
Nico Huber7bca1262012-06-15 22:28:12 +0000295 .write_aai = default_spi_write_aai,
Michael Karcherb9dbe482011-05-11 17:07:07 +0000296};
297
Uwe Hermann274a20d2011-07-21 09:18:18 +0000298/* Returns 0 upon success, a negative number upon errors. */
Thomas Heijligencc853d82021-05-04 15:32:17 +0200299static int ft2232_spi_init(void)
Paul Fox05dfbe62009-06-16 21:08:06 +0000300{
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000301 int ret;
Paul Fox05dfbe62009-06-16 21:08:06 +0000302 unsigned char buf[512];
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000303 int ft2232_vid = FTDI_VID;
304 int ft2232_type = FTDI_FT4232H_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000305 int channel_count = 4; /* Stores the number of channels of the device. */
306 enum ftdi_interface ft2232_interface = INTERFACE_A;
Samir Ibradžićb482c6d2012-05-15 22:58:19 +0000307 /*
308 * The 'H' chips can run with an internal clock of either 12 MHz or 60 MHz,
309 * but the non-H chips can only run at 12 MHz. We enable the divide-by-5
310 * prescaler on the former to run on the same speed.
311 */
312 uint8_t clock_5x = 1;
313 /* In addition to the prescaler mentioned above there is also another
314 * configurable one on all versions of the chips. Its divisor div can be
315 * set by a 16 bit value x according to the following formula:
316 * div = (1 + x) * 2 <-> x = div / 2 - 1
317 * Hence the expressible divisors are all even numbers between 2 and
318 * 2^17 (=131072) resulting in SCK frequencies of 6 MHz down to about
319 * 92 Hz for 12 MHz inputs.
320 */
321 uint32_t divisor = DEFAULT_DIVISOR;
322 int f;
Harry Johnson9fc8e252021-07-08 14:28:39 -0700323 char *arg, *arg2;
Alex Badea0b94d052010-11-10 03:18:41 +0000324 double mpsse_clk;
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000325 uint8_t cs_bits = 0x08;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200326 uint8_t aux_bits = 0x00;
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000327 uint8_t pindir = 0x0b;
328
329 struct ft2232_data *const spi_data = calloc(1, sizeof(*spi_data));
330 if (!spi_data) {
331 msg_perr("Unable to allocate space for SPI master data\n");
332 return SPI_GENERIC_ERROR;
333 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000334
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000335 arg = extract_programmer_param("type");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000336 if (arg) {
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000337 if (!strcasecmp(arg, "2232H")) {
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000338 ft2232_type = FTDI_FT2232H_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000339 channel_count = 2;
340 } else if (!strcasecmp(arg, "4232H")) {
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000341 ft2232_type = FTDI_FT4232H_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000342 channel_count = 4;
Ilya A. Volynets-Evenbakh2c714ab2012-09-26 00:47:09 +0000343 } else if (!strcasecmp(arg, "232H")) {
344 ft2232_type = FTDI_FT232H_PID;
345 channel_count = 1;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000346 } else if (!strcasecmp(arg, "jtagkey")) {
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000347 ft2232_type = AMONTEC_JTAGKEY_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000348 channel_count = 2;
Antony Pavlovb4dd40c2015-01-25 03:52:47 +0000349 /* JTAGkey(2) needs to enable its output via Bit4 / GPIOL0
350 * value: 0x18 OE=high, CS=high, DI=low, DO=low, SK=low
351 * dir: 0x1b OE=output, CS=output, DI=input, DO=output, SK=output */
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000352 cs_bits = 0x18;
Uwe Hermann70145292010-07-29 19:57:55 +0000353 pindir = 0x1b;
Samir Ibradžić7189a5f2011-10-20 23:14:10 +0000354 } else if (!strcasecmp(arg, "picotap")) {
355 ft2232_vid = GOEPEL_VID;
356 ft2232_type = GOEPEL_PICOTAP_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000357 channel_count = 2;
Uwe Hermann836b26a2011-10-14 20:33:14 +0000358 } else if (!strcasecmp(arg, "tumpa")) {
359 /* Interface A is SPI1, B is SPI2. */
360 ft2232_type = TIAO_TUMPA_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000361 channel_count = 2;
Stefan Taunerb66ed842014-04-27 05:07:35 +0000362 } else if (!strcasecmp(arg, "tumpalite")) {
363 /* Only one channel is used on lite edition */
364 ft2232_type = TIAO_TUMPA_LITE_PID;
365 channel_count = 1;
Steve Markgraf0528b7f2011-08-12 01:19:32 +0000366 } else if (!strcasecmp(arg, "busblaster")) {
367 /* In its default configuration it is a jtagkey clone */
368 ft2232_type = FTDI_FT2232H_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000369 channel_count = 2;
Steve Markgraf0528b7f2011-08-12 01:19:32 +0000370 cs_bits = 0x18;
371 pindir = 0x1b;
Alex Badeacaf2d422010-11-10 03:26:57 +0000372 } else if (!strcasecmp(arg, "openmoko")) {
373 ft2232_vid = FIC_VID;
374 ft2232_type = OPENMOKO_DBGBOARD_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000375 channel_count = 2;
Pete Batardc0207062011-06-11 12:21:37 +0000376 } else if (!strcasecmp(arg, "arm-usb-ocd")) {
377 ft2232_vid = OLIMEX_VID;
378 ft2232_type = OLIMEX_ARM_OCD_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000379 channel_count = 2;
Antony Pavlovb4dd40c2015-01-25 03:52:47 +0000380 /* arm-usb-ocd(-h) has an output buffer that needs to be enabled by pulling ADBUS4 low.
381 * value: 0x08 #OE=low, CS=high, DI=low, DO=low, SK=low
382 * dir: 0x1b #OE=output, CS=output, DI=input, DO=output, SK=output */
Paul Fertser3cf335e2011-12-20 02:08:14 +0000383 cs_bits = 0x08;
384 pindir = 0x1b;
Pete Batardc0207062011-06-11 12:21:37 +0000385 } else if (!strcasecmp(arg, "arm-usb-tiny")) {
386 ft2232_vid = OLIMEX_VID;
387 ft2232_type = OLIMEX_ARM_TINY_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000388 channel_count = 2;
Pete Batardc0207062011-06-11 12:21:37 +0000389 } else if (!strcasecmp(arg, "arm-usb-ocd-h")) {
390 ft2232_vid = OLIMEX_VID;
391 ft2232_type = OLIMEX_ARM_OCD_H_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000392 channel_count = 2;
Antony Pavlovb4dd40c2015-01-25 03:52:47 +0000393 /* See arm-usb-ocd */
Paul Fertser3cf335e2011-12-20 02:08:14 +0000394 cs_bits = 0x08;
395 pindir = 0x1b;
Pete Batardc0207062011-06-11 12:21:37 +0000396 } else if (!strcasecmp(arg, "arm-usb-tiny-h")) {
397 ft2232_vid = OLIMEX_VID;
398 ft2232_type = OLIMEX_ARM_TINY_H_PID;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000399 channel_count = 2;
Todd Broch6800c952016-02-14 15:46:00 +0000400 } else if (!strcasecmp(arg, "google-servo")) {
401 ft2232_vid = GOOGLE_VID;
402 ft2232_type = GOOGLE_SERVO_PID;
403 } else if (!strcasecmp(arg, "google-servo-v2")) {
404 ft2232_vid = GOOGLE_VID;
405 ft2232_type = GOOGLE_SERVO_V2_PID1;
406 /* Default divisor is too fast, and chip ID fails */
407 divisor = 6;
408 } else if (!strcasecmp(arg, "google-servo-v2-legacy")) {
409 ft2232_vid = GOOGLE_VID;
410 ft2232_type = GOOGLE_SERVO_V2_PID0;
Russ Dill7bd31a42019-10-30 00:40:43 -0700411 } else if (!strcasecmp(arg, "flyswatter")) {
412 ft2232_type = FTDI_FT2232H_PID;
413 channel_count = 2;
414 /* Flyswatter and Flyswatter-2 require GPIO bits 0x80
415 * and 0x40 to be driven low to enable output buffers */
416 pindir = 0xcb;
Alex Badeacaf2d422010-11-10 03:26:57 +0000417 } else {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000418 msg_perr("Error: Invalid device type specified.\n");
419 free(arg);
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000420 ret = -1;
421 goto init_err;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000422 }
423 }
424 free(arg);
Stefan Tauner3e515e22012-09-26 00:48:16 +0000425
Michael Niewöhnerb50d9eb2021-09-21 19:43:04 +0200426 /* Remember reserved pins before pindir gets modified. */
427 const uint8_t rsv_bits = pindir & 0xf0;
428
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000429 arg = extract_programmer_param("port");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000430 if (arg) {
Carl-Daniel Hailfinger9e3a6c42010-10-08 12:40:09 +0000431 switch (toupper((unsigned char)*arg)) {
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000432 case 'A':
433 ft2232_interface = INTERFACE_A;
434 break;
435 case 'B':
436 ft2232_interface = INTERFACE_B;
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000437 if (channel_count < 2)
438 channel_count = -1;
439 break;
440 case 'C':
441 ft2232_interface = INTERFACE_C;
442 if (channel_count < 3)
443 channel_count = -1;
444 break;
445 case 'D':
446 ft2232_interface = INTERFACE_D;
447 if (channel_count < 4)
448 channel_count = -1;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000449 break;
450 default:
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000451 channel_count = -1;
452 break;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000453 }
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000454 if (channel_count < 0 || strlen(arg) != 1) {
455 msg_perr("Error: Invalid channel/port/interface specified: \"%s\".\n", arg);
456 free(arg);
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000457 ret = -2;
458 goto init_err;
Stefan Taunerd7d423b2012-10-20 09:13:16 +0000459 }
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000460 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000461 free(arg);
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000462
Samir Ibradžićb482c6d2012-05-15 22:58:19 +0000463 arg = extract_programmer_param("divisor");
464 if (arg && strlen(arg)) {
465 unsigned int temp = 0;
466 char *endptr;
467 temp = strtoul(arg, &endptr, 10);
468 if (*endptr || temp < 2 || temp > 131072 || temp & 0x1) {
469 msg_perr("Error: Invalid SPI frequency divisor specified: \"%s\".\n"
470 "Valid are even values between 2 and 131072.\n", arg);
471 free(arg);
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000472 ret = -2;
473 goto init_err;
Samir Ibradžićb482c6d2012-05-15 22:58:19 +0000474 }
Elyes HAOUAS712ba3a2019-06-09 17:11:49 +0200475 divisor = (uint32_t)temp;
Samir Ibradžićb482c6d2012-05-15 22:58:19 +0000476 }
477 free(arg);
Stefan Tauner3e515e22012-09-26 00:48:16 +0000478
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200479 bool csgpiol_set = false;
Sergey Alirzaev4acc3f32018-08-01 16:39:17 +0300480 arg = extract_programmer_param("csgpiol");
481 if (arg) {
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200482 csgpiol_set = true;
483 msg_pwarn("Deprecation warning: `csgpiol` is deprecated and will be removed "
484 "in the future.\nUse `gpiolX=C` instead.\n");
485
Sergey Alirzaev4acc3f32018-08-01 16:39:17 +0300486 char *endptr;
487 unsigned int temp = strtoul(arg, &endptr, 10);
488 if (*endptr || endptr == arg || temp > 3) {
489 msg_perr("Error: Invalid GPIOL specified: \"%s\".\n"
490 "Valid values are between 0 and 3.\n", arg);
491 free(arg);
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000492 ret = -2;
493 goto init_err;
Sergey Alirzaev4acc3f32018-08-01 16:39:17 +0300494 }
Michael Niewöhnerb50d9eb2021-09-21 19:43:04 +0200495
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200496 unsigned int pin = temp + 4;
Michael Niewöhnerb50d9eb2021-09-21 19:43:04 +0200497 if (rsv_bits & 1 << pin) {
498 msg_perr("Error: Invalid GPIOL specified: \"%s\".\n"
499 "The pin is reserved on this programmer.\n",
500 arg);
501 free(arg);
502 return -2;
503 }
504
Elyes HAOUAS712ba3a2019-06-09 17:11:49 +0200505 cs_bits |= 1 << pin;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200506 pindir |= 1 << pin;
Sergey Alirzaev4acc3f32018-08-01 16:39:17 +0300507 }
508 free(arg);
509
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200510 /* gpiolX */
511 int pin;
512 for (pin = 0; pin < 4; pin++) {
513 char gpiol_param[7];
514 snprintf(gpiol_param, sizeof(gpiol_param), "gpiol%d", pin);
515 arg = extract_programmer_param(gpiol_param);
516
517 if (!arg)
518 continue;
519
520 if (csgpiol_set) {
521 msg_perr("Error: `csgpiol` and `gpiolX` are mutually exclusive.\n"
522 "Since `csgpiol` is deprecated and will be removed in the "
523 "future, use of `gpiolX=C` is recommended.\n");
524 free(arg);
525 return -2;
526 }
527
528 uint8_t bit = 1 << (pin + 4);
529 if (rsv_bits & bit) {
530 msg_perr("Error: Invalid GPIOL specified: \"gpiol%d=%s\".\n"
531 "Pin GPIOL%i is reserved on this programmer.\n",
532 pin, arg, pin);
533 free(arg);
534 return -2;
535 }
536
537 if (strlen(arg) != 1)
538 goto format_error;
539
540 switch (toupper((unsigned char)arg[0])) {
541 case 'H':
542 aux_bits |= bit;
543 pindir |= bit;
544 break;
545 case 'L':
546 pindir |= bit;
547 break;
548 case 'C':
549 cs_bits |= bit;
550 pindir |= bit;
551 break;
552 default:
553 goto format_error;
554 }
555
556 free(arg);
557 continue;
558
559format_error:
560 msg_perr("Error: Invalid GPIOL specified: \"gpiol%d=%s\".\n"
561 "Valid values are H, L and C.\n"
562 " H - Set GPIOL output high\n"
563 " L - Set GPIOL output low\n"
564 " C - Use GPIOL as additional CS# output\n",
565 pin, arg);
566
567 free(arg);
568 return -2;
569 }
570
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000571 msg_pdbg("Using device type %s %s ",
Uwe Hermann70145292010-07-29 19:57:55 +0000572 get_ft2232_vendorname(ft2232_vid, ft2232_type),
573 get_ft2232_devicename(ft2232_vid, ft2232_type));
Stefan Tauner3e515e22012-09-26 00:48:16 +0000574 msg_pdbg("channel %s.\n",
Stefan Taunerfbc71ac2012-09-26 00:46:02 +0000575 (ft2232_interface == INTERFACE_A) ? "A" :
576 (ft2232_interface == INTERFACE_B) ? "B" :
577 (ft2232_interface == INTERFACE_C) ? "C" : "D");
Paul Fox05dfbe62009-06-16 21:08:06 +0000578
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000579 struct ftdi_context *const ftdic = &spi_data->ftdi_context;
Paul Fox05dfbe62009-06-16 21:08:06 +0000580 if (ftdi_init(ftdic) < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000581 msg_perr("ftdi_init failed.\n");
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000582 ret = -3;
583 goto init_err;
Paul Fox05dfbe62009-06-16 21:08:06 +0000584 }
585
Ilya A. Volynets-Evenbakh7c36d522012-08-14 01:32:46 +0000586 if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000587 msg_perr("Unable to select channel (%s).\n", ftdi_get_error_string(ftdic));
Ilya A. Volynets-Evenbakh7c36d522012-08-14 01:32:46 +0000588 }
589
Shik Chen14fbc4b2012-09-17 00:40:54 +0000590 arg = extract_programmer_param("serial");
Harry Johnson9fc8e252021-07-08 14:28:39 -0700591 arg2 = extract_programmer_param("description");
592
593 f = ftdi_usb_open_desc(ftdic, ft2232_vid, ft2232_type, arg2, arg);
594
Shik Chen14fbc4b2012-09-17 00:40:54 +0000595 free(arg);
Harry Johnson9fc8e252021-07-08 14:28:39 -0700596 free(arg2);
Paul Fox05dfbe62009-06-16 21:08:06 +0000597
598 if (f < 0 && f != -5) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000599 msg_perr("Unable to open FTDI device: %d (%s).\n", f, ftdi_get_error_string(ftdic));
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000600 ret = -4;
601 goto init_err;
Paul Fox05dfbe62009-06-16 21:08:06 +0000602 }
603
Ilya A. Volynets-Evenbakh2c714ab2012-09-26 00:47:09 +0000604 if (ftdic->type != TYPE_2232H && ftdic->type != TYPE_4232H && ftdic->type != TYPE_232H) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000605 msg_pdbg("FTDI chip type %d is not high-speed.\n", ftdic->type);
Alex Badea0b94d052010-11-10 03:18:41 +0000606 clock_5x = 0;
607 }
608
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000609 if (ftdi_usb_reset(ftdic) < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000610 msg_perr("Unable to reset FTDI device (%s).\n", ftdi_get_error_string(ftdic));
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000611 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000612
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000613 if (ftdi_set_latency_timer(ftdic, 2) < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000614 msg_perr("Unable to set latency timer (%s).\n", ftdi_get_error_string(ftdic));
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000615 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000616
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000617 if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000618 msg_perr("Unable to set bitmode to SPI (%s).\n", ftdi_get_error_string(ftdic));
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000619 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000620
Alex Badea0b94d052010-11-10 03:18:41 +0000621 if (clock_5x) {
622 msg_pdbg("Disable divide-by-5 front stage\n");
Stefan Tauner05151b62015-01-25 23:42:57 +0000623 buf[0] = 0x8a; /* Disable divide-by-5. DIS_DIV_5 in newer libftdi */
Uwe Hermann274a20d2011-07-21 09:18:18 +0000624 if (send_buf(ftdic, buf, 1)) {
625 ret = -5;
626 goto ftdi_err;
627 }
Alex Badea0b94d052010-11-10 03:18:41 +0000628 mpsse_clk = 60.0;
629 } else {
630 mpsse_clk = 12.0;
631 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000632
Sean Nelson34b5db72010-01-10 01:08:37 +0000633 msg_pdbg("Set clock divisor\n");
Antony Pavlovb4dd40c2015-01-25 03:52:47 +0000634 buf[0] = TCK_DIVISOR;
Ilya A. Volynets-Evenbakh3464d052012-06-14 13:08:33 +0000635 buf[1] = (divisor / 2 - 1) & 0xff;
636 buf[2] = ((divisor / 2 - 1) >> 8) & 0xff;
Uwe Hermann274a20d2011-07-21 09:18:18 +0000637 if (send_buf(ftdic, buf, 3)) {
638 ret = -6;
639 goto ftdi_err;
640 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000641
Samir Ibradžićb482c6d2012-05-15 22:58:19 +0000642 msg_pdbg("MPSSE clock: %f MHz, divisor: %u, SPI clock: %f MHz\n",
643 mpsse_clk, divisor, (double)(mpsse_clk / divisor));
Paul Fox05dfbe62009-06-16 21:08:06 +0000644
Uwe Hermannc67d0372009-10-01 18:40:02 +0000645 /* Disconnect TDI/DO to TDO/DI for loopback. */
Sean Nelson34b5db72010-01-10 01:08:37 +0000646 msg_pdbg("No loopback of TDI/DO TDO/DI\n");
Antony Pavlovb4dd40c2015-01-25 03:52:47 +0000647 buf[0] = LOOPBACK_END;
Uwe Hermann274a20d2011-07-21 09:18:18 +0000648 if (send_buf(ftdic, buf, 1)) {
649 ret = -7;
650 goto ftdi_err;
651 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000652
Sean Nelson34b5db72010-01-10 01:08:37 +0000653 msg_pdbg("Set data bits\n");
Paul Fox05dfbe62009-06-16 21:08:06 +0000654 buf[0] = SET_BITS_LOW;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200655 buf[1] = cs_bits | aux_bits;
Jörg Fischer6529b9f2010-07-29 15:54:53 +0000656 buf[2] = pindir;
Uwe Hermann274a20d2011-07-21 09:18:18 +0000657 if (send_buf(ftdic, buf, 3)) {
658 ret = -8;
659 goto ftdi_err;
660 }
Paul Fox05dfbe62009-06-16 21:08:06 +0000661
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000662 spi_data->cs_bits = cs_bits;
Michael Niewöhnerece63c82021-09-21 20:15:32 +0200663 spi_data->aux_bits = aux_bits;
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000664 spi_data->pindir = pindir;
665 spi_master_ft2232.data = spi_data;
666
667 if (register_shutdown(ft2232_shutdown, spi_data)) {
668 ret = -9;
669 goto ftdi_err;
670 }
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000671 register_spi_master(&spi_master_ft2232);
Paul Fox05dfbe62009-06-16 21:08:06 +0000672
673 return 0;
Uwe Hermann274a20d2011-07-21 09:18:18 +0000674
675ftdi_err:
676 if ((f = ftdi_usb_close(ftdic)) < 0) {
Stefan Tauner3e515e22012-09-26 00:48:16 +0000677 msg_perr("Unable to close FTDI device: %d (%s)\n", f, ftdi_get_error_string(ftdic));
Uwe Hermann274a20d2011-07-21 09:18:18 +0000678 }
Anastasia Klimchuke8106ba2021-04-12 10:05:57 +1000679init_err:
680 free(spi_data);
Uwe Hermann274a20d2011-07-21 09:18:18 +0000681 return ret;
Paul Fox05dfbe62009-06-16 21:08:06 +0000682}
683
Thomas Heijligencc853d82021-05-04 15:32:17 +0200684const struct programmer_entry programmer_ft2232_spi = {
685 .name = "ft2232_spi",
686 .type = USB,
687 .devs.dev = devs_ft2232spi,
688 .init = ft2232_spi_init,
689 .map_flash_region = fallback_map,
690 .unmap_flash_region = fallback_unmap,
691 .delay = internal_delay,
692};
Paul Fox05dfbe62009-06-16 21:08:06 +0000693#endif