7d2fac08900a0f4123d107fb7535d89dce7fe6f5
[openocd.git] / src / jtag / ft2232.c
1 /***************************************************************************
2 * Copyright (C) 2004, 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
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 *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #if IS_CYGWIN == 1
25 #include "windows.h"
26 #undef ERROR
27 #endif
28
29 #include "replacements.h"
30
31 /* project specific includes */
32 #include "log.h"
33 #include "types.h"
34 #include "jtag.h"
35 #include "configuration.h"
36 #include "time_support.h"
37
38 /* system includes */
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 /* FT2232 access library includes */
44 #if BUILD_FT2232_FTD2XX == 1
45 #include <ftd2xx.h>
46 #elif BUILD_FT2232_LIBFTDI == 1
47 #include <ftdi.h>
48 #endif
49
50 #include <sys/time.h>
51 #include <time.h>
52
53 /* enable this to debug io latency
54 */
55 #if 0
56 #define _DEBUG_USB_IO_
57 #endif
58
59 /* enable this to debug communication
60 */
61 #if 0
62 #define _DEBUG_USB_COMMS_
63 #endif
64
65 int ft2232_execute_queue(void);
66
67 int ft2232_speed(int speed);
68 int ft2232_register_commands(struct command_context_s *cmd_ctx);
69 int ft2232_init(void);
70 int ft2232_quit(void);
71
72 int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
73 int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
74 int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
75
76 char *ft2232_device_desc = NULL;
77 char *ft2232_layout = NULL;
78 u16 ft2232_vid = 0x0403;
79 u16 ft2232_pid = 0x6010;
80
81 typedef struct ft2232_layout_s
82 {
83 char* name;
84 int(*init)(void);
85 void(*reset)(int trst, int srst);
86 void(*blink)(void);
87 } ft2232_layout_t;
88
89 /* init procedures for supported layouts */
90 int usbjtag_init(void);
91 int jtagkey_init(void);
92 int olimex_jtag_init(void);
93
94 /* reset procedures for supported layouts */
95 void usbjtag_reset(int trst, int srst);
96 void jtagkey_reset(int trst, int srst);
97 void olimex_jtag_reset(int trst, int srst);
98
99 /* blink procedures for layouts that support a blinking led */
100 void olimex_jtag_blink(void);
101
102 ft2232_layout_t ft2232_layouts[] =
103 {
104 {"usbjtag", usbjtag_init, usbjtag_reset, NULL},
105 {"jtagkey", jtagkey_init, jtagkey_reset, NULL},
106 {"jtagkey_prototype_v1", jtagkey_init, jtagkey_reset, NULL},
107 {"signalyzer", usbjtag_init, usbjtag_reset, NULL},
108 {"olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink},
109 {NULL, NULL, NULL},
110 };
111
112 static u8 nTRST, nTRSTnOE, nSRST, nSRSTnOE;
113
114 static ft2232_layout_t *layout;
115 static u8 low_output = 0x0;
116 static u8 low_direction = 0x0;
117 static u8 high_output = 0x0;
118 static u8 high_direction = 0x0;
119
120 #if BUILD_FT2232_FTD2XX == 1
121 static FT_HANDLE ftdih = NULL;
122 #elif BUILD_FT2232_LIBFTDI == 1
123 static struct ftdi_context ftdic;
124 #endif
125
126 static u8 *ft2232_buffer = NULL;
127 static int ft2232_buffer_size = 0;
128 static int ft2232_read_pointer = 0;
129 static int ft2232_expect_read = 0;
130 #define FT2232_BUFFER_SIZE 131072
131 #define BUFFER_ADD ft2232_buffer[ft2232_buffer_size++]
132 #define BUFFER_READ ft2232_buffer[ft2232_read_pointer++]
133
134 jtag_interface_t ft2232_interface =
135 {
136
137 .name = "ft2232",
138
139 .execute_queue = ft2232_execute_queue,
140
141 .support_pathmove = 1,
142
143 .speed = ft2232_speed,
144 .register_commands = ft2232_register_commands,
145 .init = ft2232_init,
146 .quit = ft2232_quit,
147 };
148
149 int ft2232_write(u8 *buf, int size, u32* bytes_written)
150 {
151 #if BUILD_FT2232_FTD2XX == 1
152 FT_STATUS status;
153 DWORD dw_bytes_written;
154 if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK)
155 {
156 *bytes_written = dw_bytes_written;
157 ERROR("FT_Write returned: %i", status);
158 return ERROR_JTAG_DEVICE_ERROR;
159 }
160 else
161 {
162 *bytes_written = dw_bytes_written;
163 return ERROR_OK;
164 }
165 #elif BUILD_FT2232_LIBFTDI == 1
166 int retval;
167 if ((retval = ftdi_write_data(&ftdic, buf, size)) < 0)
168 {
169 *bytes_written = 0;
170 ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic));
171 return ERROR_JTAG_DEVICE_ERROR;
172 }
173 else
174 {
175 *bytes_written = retval;
176 return ERROR_OK;
177 }
178 #endif
179 }
180
181 int ft2232_read(u8* buf, int size, u32* bytes_read)
182 {
183 #if BUILD_FT2232_FTD2XX == 1
184 DWORD dw_bytes_read;
185 FT_STATUS status;
186 if ((status = FT_Read(ftdih, buf, size, &dw_bytes_read)) != FT_OK)
187 {
188 *bytes_read = dw_bytes_read;
189 ERROR("FT_Read returned: %i", status);
190 return ERROR_JTAG_DEVICE_ERROR;
191 }
192 *bytes_read = dw_bytes_read;
193 return ERROR_OK;
194
195 #elif BUILD_FT2232_LIBFTDI == 1
196 int retval;
197 int timeout = 100;
198 *bytes_read = 0;
199
200 while ((*bytes_read < size) && timeout--)
201 {
202 if ((retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read)) < 0)
203 {
204 *bytes_read = 0;
205 ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic));
206 return ERROR_JTAG_DEVICE_ERROR;
207 }
208 *bytes_read += retval;
209 }
210 return ERROR_OK;
211 #endif
212 }
213
214 int ft2232_speed(int speed)
215 {
216 u8 buf[3];
217 int retval;
218 u32 bytes_written;
219
220 buf[0] = 0x86; /* command "set divisor" */
221 buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
222 buf[2] = (speed >> 8) & 0xff; /* valueH */
223
224 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
225 if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
226 {
227 ERROR("couldn't set FT2232 TCK speed");
228 return retval;
229 }
230
231 return ERROR_OK;
232 }
233
234 int ft2232_register_commands(struct command_context_s *cmd_ctx)
235 {
236 register_command(cmd_ctx, NULL, "ft2232_device_desc", ft2232_handle_device_desc_command,
237 COMMAND_CONFIG, NULL);
238 register_command(cmd_ctx, NULL, "ft2232_layout", ft2232_handle_layout_command,
239 COMMAND_CONFIG, NULL);
240 register_command(cmd_ctx, NULL, "ft2232_vid_pid", ft2232_handle_vid_pid_command,
241 COMMAND_CONFIG, NULL);
242 return ERROR_OK;
243 }
244
245 void ft2232_end_state(state)
246 {
247 if (tap_move_map[state] != -1)
248 end_state = state;
249 else
250 {
251 ERROR("BUG: %i is not a valid end state", state);
252 exit(-1);
253 }
254 }
255
256 void ft2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
257 {
258 int num_bytes = ((scan_size + 7) / 8);
259 int bits_left = scan_size;
260 int cur_byte = 0;
261
262 while(num_bytes-- > 1)
263 {
264 buffer[cur_byte] = BUFFER_READ;
265 cur_byte++;
266 bits_left -= 8;
267 }
268
269 buffer[cur_byte] = 0x0;
270
271 if (bits_left > 1)
272 {
273 buffer[cur_byte] = BUFFER_READ >> 1;
274 }
275
276 buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
277
278 }
279
280 void ft2232_debug_dump_buffer(void)
281 {
282 int i;
283 char line[256];
284 char *line_p = line;
285
286 for (i = 0; i < ft2232_buffer_size; i++)
287 {
288 line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]);
289 if (i % 16 == 15)
290 {
291 DEBUG("%s", line);
292 line_p = line;
293 }
294 }
295
296 if (line_p != line)
297 DEBUG("%s", line);
298 }
299
300 int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
301 {
302 jtag_command_t *cmd;
303 u8 *buffer;
304 int scan_size;
305 enum scan_type type;
306 int retval;
307 u32 bytes_written;
308 u32 bytes_read;
309
310 #ifdef _DEBUG_USB_IO_
311 struct timeval start, inter, inter2, end;
312 struct timeval d_inter, d_inter2, d_end;
313 #endif
314
315 #ifdef _DEBUG_USB_COMMS_
316 DEBUG("write buffer (size %i):", ft2232_buffer_size);
317 ft2232_debug_dump_buffer();
318 #endif
319
320 #ifdef _DEBUG_USB_IO_
321 gettimeofday(&start, NULL);
322 #endif
323
324 if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK)
325 {
326 ERROR("couldn't write MPSSE commands to FT2232");
327 exit(-1);
328 }
329
330 #ifdef _DEBUG_USB_IO_
331 gettimeofday(&inter, NULL);
332 #endif
333
334 if (ft2232_expect_read)
335 {
336 int timeout = 100;
337 ft2232_buffer_size = 0;
338
339 #ifdef _DEBUG_USB_IO_
340 gettimeofday(&inter2, NULL);
341 #endif
342
343 if ((retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read)) != ERROR_OK)
344 {
345 ERROR("couldn't read from FT2232");
346 exit(-1);
347 }
348
349 #ifdef _DEBUG_USB_IO_
350 gettimeofday(&end, NULL);
351
352 timeval_subtract(&d_inter, &inter, &start);
353 timeval_subtract(&d_inter2, &inter2, &start);
354 timeval_subtract(&d_end, &end, &start);
355
356 INFO("inter: %i.%i, inter2: %i.%i end: %i.%i", d_inter.tv_sec, d_inter.tv_usec, d_inter2.tv_sec, d_inter2.tv_usec, d_end.tv_sec, d_end.tv_usec);
357 #endif
358
359
360 ft2232_buffer_size = bytes_read;
361
362 if (ft2232_expect_read != ft2232_buffer_size)
363 {
364 ERROR("ft2232_expect_read (%i) != ft2232_buffer_size (%i) (%i retries)", ft2232_expect_read, ft2232_buffer_size, 100 - timeout);
365 ft2232_debug_dump_buffer();
366
367 exit(-1);
368 }
369
370 #ifdef _DEBUG_USB_COMMS_
371 DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ft2232_buffer_size);
372 ft2232_debug_dump_buffer();
373 #endif
374 }
375
376 ft2232_expect_read = 0;
377 ft2232_read_pointer = 0;
378
379 cmd = first;
380 while (cmd != last)
381 {
382 switch (cmd->type)
383 {
384 case JTAG_SCAN:
385 type = jtag_scan_type(cmd->cmd.scan);
386 if (type != SCAN_OUT)
387 {
388 scan_size = jtag_scan_size(cmd->cmd.scan);
389 buffer = calloc(CEIL(scan_size, 8), 1);
390 ft2232_read_scan(type, buffer, scan_size);
391 jtag_read_buffer(buffer, cmd->cmd.scan);
392 free(buffer);
393 }
394 break;
395 default:
396 break;
397 }
398 cmd = cmd->next;
399 }
400
401 ft2232_buffer_size = 0;
402
403 return ERROR_OK;
404 }
405
406 void ft2232_add_pathmove(pathmove_command_t *cmd)
407 {
408 int num_states = cmd->num_states;
409 u8 tms_byte;
410 int state_count;
411
412 state_count = 0;
413 while (num_states)
414 {
415 tms_byte = 0x0;
416 int bit_count = 0;
417
418 /* command "Clock Data to TMS/CS Pin (no Read)" */
419 BUFFER_ADD = 0x4b;
420 /* number of states remaining */
421 BUFFER_ADD = (num_states % 7) - 1;
422
423 while (num_states % 7)
424 {
425 if (tap_transitions[cur_state].low == cmd->path[state_count])
426 buf_set_u32(&tms_byte, bit_count++, 1, 0x0);
427 else if (tap_transitions[cur_state].high == cmd->path[state_count])
428 buf_set_u32(&tms_byte, bit_count++, 1, 0x1);
429 else
430 {
431 ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]);
432 exit(-1);
433 }
434
435 cur_state = cmd->path[state_count];
436 state_count++;
437 num_states--;
438 }
439
440 BUFFER_ADD = tms_byte;
441 }
442
443 end_state = cur_state;
444 }
445
446 void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
447 {
448 int num_bytes = (scan_size + 7) / 8;
449 int bits_left = scan_size;
450 int cur_byte = 0;
451 int last_bit;
452
453 if ((!ir_scan && (cur_state != TAP_SD)) || (ir_scan && (cur_state != TAP_SI)))
454 {
455 /* command "Clock Data to TMS/CS Pin (no Read)" */
456 BUFFER_ADD = 0x4b;
457 /* scan 7 bit */
458 BUFFER_ADD = 0x6;
459 /* TMS data bits */
460 if (ir_scan)
461 {
462 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
463 cur_state = TAP_SI;
464 }
465 else
466 {
467 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
468 cur_state = TAP_SD;
469 }
470 //DEBUG("added TMS scan (no read)");
471 }
472
473 /* add command for complete bytes */
474 if (num_bytes > 1)
475 {
476 if (type == SCAN_IO)
477 {
478 /* Clock Data Bytes In and Out LSB First */
479 BUFFER_ADD = 0x39;
480 //DEBUG("added TDI bytes (io %i)", num_bytes);
481 }
482 else if (type == SCAN_OUT)
483 {
484 /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
485 BUFFER_ADD = 0x19;
486 //DEBUG("added TDI bytes (o)");
487 }
488 else if (type == SCAN_IN)
489 {
490 /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
491 BUFFER_ADD = 0x28;
492 //DEBUG("added TDI bytes (i %i)", num_bytes);
493 }
494 BUFFER_ADD = (num_bytes-2) & 0xff;
495 BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
496 }
497 if (type != SCAN_IN)
498 {
499 /* add complete bytes */
500 while(num_bytes-- > 1)
501 {
502 BUFFER_ADD = buffer[cur_byte];
503 cur_byte++;
504 bits_left -= 8;
505 }
506 }
507 if (type == SCAN_IN)
508 {
509 bits_left -= 8 * (num_bytes - 1);
510 }
511
512 /* the most signifcant bit is scanned during TAP movement */
513 if (type != SCAN_IN)
514 last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
515 else
516 last_bit = 0;
517
518 /* process remaining bits but the last one */
519 if (bits_left > 1)
520 {
521 if (type == SCAN_IO)
522 {
523 /* Clock Data Bits In and Out LSB First */
524 BUFFER_ADD = 0x3b;
525 //DEBUG("added TDI bits (io) %i", bits_left - 1);
526 }
527 else if (type == SCAN_OUT)
528 {
529 /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
530 BUFFER_ADD = 0x1b;
531 //DEBUG("added TDI bits (o)");
532 }
533 else if (type == SCAN_IN)
534 {
535 /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
536 BUFFER_ADD = 0x2a;
537 //DEBUG("added TDI bits (i %i)", bits_left - 1);
538 }
539 BUFFER_ADD = bits_left - 2;
540 if (type != SCAN_IN)
541 BUFFER_ADD = buffer[cur_byte];
542 }
543
544 /* move from Shift-IR/DR to end state */
545 if (type != SCAN_OUT)
546 {
547 /* Clock Data to TMS/CS Pin with Read */
548 BUFFER_ADD = 0x6b;
549 //DEBUG("added TMS scan (read)");
550 }
551 else
552 {
553 /* Clock Data to TMS/CS Pin (no Read) */
554 BUFFER_ADD = 0x4b;
555 //DEBUG("added TMS scan (no read)");
556 }
557 BUFFER_ADD = 0x6;
558 BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
559 cur_state = end_state;
560
561 }
562
563 int ft2232_predict_scan_out(int scan_size, enum scan_type type)
564 {
565 int predicted_size = 3;
566
567 if (cur_state != TAP_SD)
568 predicted_size += 3;
569
570 if (type == SCAN_IN) /* only from device to host */
571 {
572 /* complete bytes */
573 predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
574 /* remaining bits - 1 (up to 7) */
575 predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
576 }
577 else /* host to device, or bidirectional */
578 {
579 /* complete bytes */
580 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
581 /* remaining bits -1 (up to 7) */
582 predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
583 }
584
585 return predicted_size;
586 }
587
588 int ft2232_predict_scan_in(int scan_size, enum scan_type type)
589 {
590 int predicted_size = 0;
591
592 if (type != SCAN_OUT)
593 {
594 /* complete bytes */
595 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
596 /* remaining bits - 1 */
597 predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
598 /* last bit (from TMS scan) */
599 predicted_size += 1;
600 }
601
602 //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
603
604 return predicted_size;
605 }
606
607 void usbjtag_reset(int trst, int srst)
608 {
609 if (trst == 1)
610 {
611 cur_state = TAP_TLR;
612 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
613 low_direction |= nTRSTnOE; /* switch to output pin (output is low) */
614 else
615 low_output &= ~nTRST; /* switch output low */
616 }
617 else if (trst == 0)
618 {
619 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
620 low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */
621 else
622 low_output |= nTRST; /* switch output high */
623 }
624
625 if (srst == 1)
626 {
627 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
628 low_output &= ~nSRST; /* switch output low */
629 else
630 low_direction |= nSRSTnOE; /* switch to output pin (output is low) */
631 }
632 else if (srst == 0)
633 {
634 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
635 low_output |= nSRST; /* switch output high */
636 else
637 low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */
638 }
639
640 /* command "set data bits low byte" */
641 BUFFER_ADD = 0x80;
642 BUFFER_ADD = low_output;
643 BUFFER_ADD = low_direction;
644
645 }
646
647 void jtagkey_reset(int trst, int srst)
648 {
649 if (trst == 1)
650 {
651 cur_state = TAP_TLR;
652 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
653 high_output &= ~nTRSTnOE;
654 else
655 high_output &= ~nTRST;
656 }
657 else if (trst == 0)
658 {
659 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
660 high_output |= nTRSTnOE;
661 else
662 high_output |= nTRST;
663 }
664
665 if (srst == 1)
666 {
667 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
668 high_output &= ~nSRST;
669 else
670 high_output &= ~nSRSTnOE;
671 }
672 else if (srst == 0)
673 {
674 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
675 high_output |= nSRST;
676 else
677 high_output |= nSRSTnOE;
678 }
679
680 /* command "set data bits high byte" */
681 BUFFER_ADD = 0x82;
682 BUFFER_ADD = high_output;
683 BUFFER_ADD = high_direction;
684 DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
685 }
686
687 void olimex_jtag_reset(int trst, int srst)
688 {
689 if (trst == 1)
690 {
691 cur_state = TAP_TLR;
692 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
693 high_output &= ~nTRSTnOE;
694 else
695 high_output &= ~nTRST;
696 }
697 else if (trst == 0)
698 {
699 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
700 high_output |= nTRSTnOE;
701 else
702 high_output |= nTRST;
703 }
704
705 if (srst == 1)
706 {
707 high_output |= nSRST;
708 }
709 else if (srst == 0)
710 {
711 high_output &= ~nSRST;
712 }
713
714 /* command "set data bits high byte" */
715 BUFFER_ADD = 0x82;
716 BUFFER_ADD = high_output;
717 BUFFER_ADD = high_direction;
718 DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
719 }
720
721 int ft2232_execute_queue()
722 {
723 jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
724 jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
725 u8 *buffer;
726 int scan_size; /* size of IR or DR scan */
727 enum scan_type type;
728 int i;
729 int predicted_size = 0;
730 int require_send = 0;
731
732 ft2232_buffer_size = 0;
733 ft2232_expect_read = 0;
734
735 /* blink, if the current layout has that feature */
736 if (layout->blink)
737 layout->blink();
738
739 while (cmd)
740 {
741 switch(cmd->type)
742 {
743 case JTAG_END_STATE:
744 if (cmd->cmd.end_state->end_state != -1)
745 ft2232_end_state(cmd->cmd.end_state->end_state);
746 break;
747 case JTAG_RESET:
748 /* only send the maximum buffer size that FT2232C can handle */
749 predicted_size = 3;
750 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
751 {
752 ft2232_send_and_recv(first_unsent, cmd);
753 require_send = 0;
754 first_unsent = cmd;
755 }
756
757 layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
758 require_send = 1;
759
760 #ifdef _DEBUG_JTAG_IO_
761 DEBUG("trst: %i, srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
762 #endif
763 break;
764 case JTAG_RUNTEST:
765 /* only send the maximum buffer size that FT2232C can handle */
766 predicted_size = 0;
767 if (cur_state != TAP_RTI)
768 predicted_size += 3;
769 predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
770 if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
771 predicted_size += 3;
772 if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
773 predicted_size += 3;
774 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
775 {
776 ft2232_send_and_recv(first_unsent, cmd);
777 require_send = 0;
778 first_unsent = cmd;
779 }
780 if (cur_state != TAP_RTI)
781 {
782 /* command "Clock Data to TMS/CS Pin (no Read)" */
783 BUFFER_ADD = 0x4b;
784 /* scan 7 bit */
785 BUFFER_ADD = 0x6;
786 /* TMS data bits */
787 BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
788 cur_state = TAP_RTI;
789 require_send = 1;
790 }
791 i = cmd->cmd.runtest->num_cycles;
792 while (i > 0)
793 {
794 /* command "Clock Data to TMS/CS Pin (no Read)" */
795 BUFFER_ADD = 0x4b;
796 /* scan 7 bit */
797 BUFFER_ADD = (i > 7) ? 6 : (i - 1);
798 /* TMS data bits */
799 BUFFER_ADD = 0x0;
800 cur_state = TAP_RTI;
801 i -= (i > 7) ? 7 : i;
802 //DEBUG("added TMS scan (no read)");
803 }
804 if (cmd->cmd.runtest->end_state != -1)
805 ft2232_end_state(cmd->cmd.runtest->end_state);
806 if (cur_state != end_state)
807 {
808 /* command "Clock Data to TMS/CS Pin (no Read)" */
809 BUFFER_ADD = 0x4b;
810 /* scan 7 bit */
811 BUFFER_ADD = 0x6;
812 /* TMS data bits */
813 BUFFER_ADD = TAP_MOVE(cur_state, end_state);
814 cur_state = end_state;
815 //DEBUG("added TMS scan (no read)");
816 }
817 require_send = 1;
818 #ifdef _DEBUG_JTAG_IO_
819 DEBUG("runtest: %i, end in %i", cmd->cmd.runtest->num_cycles, end_state);
820 #endif
821 break;
822 case JTAG_STATEMOVE:
823 /* only send the maximum buffer size that FT2232C can handle */
824 predicted_size = 3;
825 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
826 {
827 ft2232_send_and_recv(first_unsent, cmd);
828 require_send = 0;
829 first_unsent = cmd;
830 }
831 if (cmd->cmd.statemove->end_state != -1)
832 ft2232_end_state(cmd->cmd.statemove->end_state);
833 /* command "Clock Data to TMS/CS Pin (no Read)" */
834 BUFFER_ADD = 0x4b;
835 /* scan 7 bit */
836 BUFFER_ADD = 0x6;
837 /* TMS data bits */
838 BUFFER_ADD = TAP_MOVE(cur_state, end_state);
839 //DEBUG("added TMS scan (no read)");
840 cur_state = end_state;
841 require_send = 1;
842 #ifdef _DEBUG_JTAG_IO_
843 DEBUG("statemove: %i", end_state);
844 #endif
845 break;
846 case JTAG_PATHMOVE:
847 /* only send the maximum buffer size that FT2232C can handle */
848 predicted_size = 3 * CEIL(cmd->cmd.pathmove->num_states, 7);
849 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
850 {
851 ft2232_send_and_recv(first_unsent, cmd);
852 require_send = 0;
853 first_unsent = cmd;
854 }
855 ft2232_add_pathmove(cmd->cmd.pathmove);
856 require_send = 1;
857 #ifdef _DEBUG_JTAG_IO_
858 DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
859 #endif
860 break;
861 case JTAG_SCAN:
862 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
863 type = jtag_scan_type(cmd->cmd.scan);
864 predicted_size = ft2232_predict_scan_out(scan_size, type);
865 if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
866 {
867 DEBUG("ftd2xx buffer size reached, sending queued commands (first_unsent: %x, cmd: %x)", first_unsent, cmd);
868 ft2232_send_and_recv(first_unsent, cmd);
869 require_send = 0;
870 first_unsent = cmd;
871 }
872 ft2232_expect_read += ft2232_predict_scan_in(scan_size, type);
873 //DEBUG("new read size: %i", ft2232_expect_read);
874 if (cmd->cmd.scan->end_state != -1)
875 ft2232_end_state(cmd->cmd.scan->end_state);
876 ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
877 require_send = 1;
878 if (buffer)
879 free(buffer);
880 #ifdef _DEBUG_JTAG_IO_
881 DEBUG("%s scan, %i bit, end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, end_state);
882 #endif
883 break;
884 case JTAG_SLEEP:
885 ft2232_send_and_recv(first_unsent, cmd);
886 first_unsent = cmd->next;
887 jtag_sleep(cmd->cmd.sleep->us);
888 #ifdef _DEBUG_JTAG_IO_
889 DEBUG("sleep %i usec", cmd->cmd.sleep->us);
890 #endif
891 break;
892 default:
893 ERROR("BUG: unknown JTAG command type encountered");
894 exit(-1);
895 }
896 cmd = cmd->next;
897 }
898
899 if (require_send > 0)
900 ft2232_send_and_recv(first_unsent, cmd);
901
902 return ERROR_OK;
903 }
904
905 int ft2232_init(void)
906 {
907 u8 latency_timer;
908 u8 buf[1];
909 int retval;
910 u32 bytes_written;
911
912 #if BUILD_FT2232_FTD2XX == 1
913 FT_STATUS status;
914 #endif
915
916 ft2232_layout_t *cur_layout = ft2232_layouts;
917
918 if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
919 {
920 ft2232_layout = "usbjtag";
921 WARNING("No ft2232 layout specified, using default 'usbjtag'");
922 }
923
924 while (cur_layout->name)
925 {
926 if (strcmp(cur_layout->name, ft2232_layout) == 0)
927 {
928 layout = cur_layout;
929 break;
930 }
931 cur_layout++;
932 }
933
934 if (!layout)
935 {
936 ERROR("No matching layout found for %s", ft2232_layout);
937 return ERROR_JTAG_INIT_FAILED;
938 }
939
940 #if BUILD_FT2232_FTD2XX == 1
941 DEBUG("'ft2232' interface using FTD2XX with '%s' layout", ft2232_layout);
942 #elif BUILD_FT2232_LIBFTDI == 1
943 DEBUG("'ft2232' interface using libftdi with '%s' layout", ft2232_layout);
944 #endif
945
946 #if BUILD_FT2232_FTD2XX == 1
947 /* Open by device description */
948 if (ft2232_device_desc == NULL)
949 {
950 WARNING("no ftd2xx device description specified, using default 'Dual RS232'");
951 ft2232_device_desc = "Dual RS232";
952 }
953
954 #if IS_WIN32 == 0
955 /* Add non-standard Vid/Pid to the linux driver */
956 if ((status = FT_SetVIDPID(ft2232_vid, ft2232_pid)) != FT_OK)
957 {
958 WARNING("couldn't add %4.4x:%4.4x", ft2232_vid, ft2232_pid);
959 }
960 #endif
961
962 if ((status = FT_OpenEx(ft2232_device_desc, FT_OPEN_BY_DESCRIPTION, &ftdih)) != FT_OK)
963 {
964 DWORD num_devices;
965
966 ERROR("unable to open ftdi device: %i", status);
967 status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
968 if (status == FT_OK)
969 {
970 char **desc_array = malloc(sizeof(char*) * (num_devices + 1));
971 int i;
972
973 for (i = 0; i < num_devices; i++)
974 desc_array[i] = malloc(64);
975 desc_array[num_devices] = NULL;
976
977 status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
978
979 if (status == FT_OK)
980 {
981 ERROR("ListDevices: %d\n", num_devices);
982 for (i = 0; i < num_devices; i++)
983 ERROR("%i: %s", i, desc_array[i]);
984 }
985
986 for (i = 0; i < num_devices; i++)
987 free(desc_array[i]);
988 free(desc_array);
989 }
990 else
991 {
992 printf("ListDevices: NONE\n");
993 }
994 return ERROR_JTAG_INIT_FAILED;
995 }
996
997 if ((status = FT_SetLatencyTimer(ftdih, 2)) != FT_OK)
998 {
999 ERROR("unable to set latency timer: %i", status);
1000 return ERROR_JTAG_INIT_FAILED;
1001 }
1002
1003 if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK)
1004 {
1005 ERROR("unable to get latency timer: %i", status);
1006 return ERROR_JTAG_INIT_FAILED;
1007 }
1008 else
1009 {
1010 DEBUG("current latency timer: %i", latency_timer);
1011 }
1012
1013 if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK)
1014 {
1015 ERROR("unable to enable bit i/o mode: %i", status);
1016 return ERROR_JTAG_INIT_FAILED;
1017 }
1018 #elif BUILD_FT2232_LIBFTDI == 1
1019 if (ftdi_init(&ftdic) < 0)
1020 return ERROR_JTAG_INIT_FAILED;
1021
1022 /* context, vendor id, product id */
1023 if (ftdi_usb_open(&ftdic, ft2232_vid, ft2232_pid) < 0)
1024 {
1025 ERROR("unable to open ftdi device: %s", ftdic.error_str);
1026 return ERROR_JTAG_INIT_FAILED;
1027 }
1028
1029 if (ftdi_usb_reset(&ftdic) < 0)
1030 {
1031 ERROR("unable to reset ftdi device");
1032 return ERROR_JTAG_INIT_FAILED;
1033 }
1034
1035 if (ftdi_set_latency_timer(&ftdic, 2) < 0)
1036 {
1037 ERROR("unable to set latency timer");
1038 return ERROR_JTAG_INIT_FAILED;
1039 }
1040
1041 if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0)
1042 {
1043 ERROR("unable to get latency timer");
1044 return ERROR_JTAG_INIT_FAILED;
1045 }
1046 else
1047 {
1048 DEBUG("current latency timer: %i", latency_timer);
1049 }
1050
1051 ftdic.bitbang_mode = 0; /* Reset controller */
1052 ftdi_enable_bitbang(&ftdic, 0x0b); /* ctx, JTAG I/O mask */
1053
1054 ftdic.bitbang_mode = 2; /* MPSSE mode */
1055 ftdi_enable_bitbang(&ftdic, 0x0b); /* ctx, JTAG I/O mask */
1056 #endif
1057
1058 ft2232_buffer_size = 0;
1059 ft2232_buffer = malloc(FT2232_BUFFER_SIZE);
1060
1061 if (layout->init() != ERROR_OK)
1062 return ERROR_JTAG_INIT_FAILED;
1063
1064 ft2232_speed(jtag_speed);
1065
1066 buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */
1067 if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1))
1068 {
1069 ERROR("couldn't write to FT2232 to disable loopback");
1070 return ERROR_JTAG_INIT_FAILED;
1071 }
1072
1073 #if BUILD_FT2232_FTD2XX == 1
1074 if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
1075 {
1076 ERROR("error purging ftd2xx device: %i", status);
1077 return ERROR_JTAG_INIT_FAILED;
1078 }
1079 #elif BUILD_FT2232_LIBFTDI == 1
1080 if (ftdi_usb_purge_buffers(&ftdic) < 0)
1081 {
1082 ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
1083 return ERROR_JTAG_INIT_FAILED;
1084 }
1085 #endif
1086
1087 return ERROR_OK;
1088 }
1089
1090 int usbjtag_init(void)
1091 {
1092 u8 buf[3];
1093 u32 bytes_written;
1094
1095 low_output = 0x08;
1096 low_direction = 0x0b;
1097
1098 if (strcmp(ft2232_layout, "usbjtag") == 0)
1099 {
1100 nTRST = 0x10;
1101 nTRSTnOE = 0x10;
1102 nSRST = 0x40;
1103 nSRSTnOE = 0x40;
1104 }
1105 else if (strcmp(ft2232_layout, "signalyzer") == 0)
1106 {
1107 nTRST = 0x10;
1108 nTRSTnOE = 0x10;
1109 nSRST = 0x20;
1110 nSRSTnOE = 0x20;
1111 }
1112 else
1113 {
1114 ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout);
1115 return ERROR_JTAG_INIT_FAILED;
1116 }
1117
1118 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
1119 {
1120 low_direction &= ~nTRSTnOE; /* nTRST input */
1121 low_output &= ~nTRST; /* nTRST = 0 */
1122 }
1123 else
1124 {
1125 low_direction |= nTRSTnOE; /* nTRST output */
1126 low_output |= nTRST; /* nTRST = 1 */
1127 }
1128
1129 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
1130 {
1131 low_direction |= nSRSTnOE; /* nSRST output */
1132 low_output |= nSRST; /* nSRST = 1 */
1133 }
1134 else
1135 {
1136 low_direction &= ~nSRSTnOE; /* nSRST input */
1137 low_output &= ~nSRST; /* nSRST = 0 */
1138 }
1139
1140 /* initialize low byte for jtag */
1141 buf[0] = 0x80; /* command "set data bits low byte" */
1142 buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
1143 buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
1144 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1145
1146 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1147 {
1148 ERROR("couldn't initialize FT2232 with 'USBJTAG' layout");
1149 return ERROR_JTAG_INIT_FAILED;
1150 }
1151
1152 return ERROR_OK;
1153 }
1154
1155 int jtagkey_init(void)
1156 {
1157 u8 buf[3];
1158 u32 bytes_written;
1159
1160 low_output = 0x08;
1161 low_direction = 0x1b;
1162
1163 /* initialize low byte for jtag */
1164 buf[0] = 0x80; /* command "set data bits low byte" */
1165 buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
1166 buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
1167 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1168
1169 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1170 {
1171 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1172 return ERROR_JTAG_INIT_FAILED;
1173 }
1174
1175 if (strcmp(layout->name, "jtagkey") == 0)
1176 {
1177 nTRST = 0x01;
1178 nTRSTnOE = 0x4;
1179 nSRST = 0x02;
1180 nSRSTnOE = 0x08;
1181 }
1182 else if (strcmp(layout->name, "jtagkey_prototype_v1") == 0)
1183 {
1184 nTRST = 0x02;
1185 nTRSTnOE = 0x1;
1186 nSRST = 0x08;
1187 nSRSTnOE = 0x04;
1188 }
1189 else
1190 {
1191 ERROR("BUG: jtagkey_init called for non jtagkey layout");
1192 exit(-1);
1193 }
1194
1195 high_output = 0x0;
1196 high_direction = 0x0f;
1197
1198 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
1199 {
1200 high_output |= nTRSTnOE;
1201 high_output &= ~nTRST;
1202 }
1203 else
1204 {
1205 high_output &= ~nTRSTnOE;
1206 high_output |= nTRST;
1207 }
1208
1209 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
1210 {
1211 high_output &= ~nSRSTnOE;
1212 high_output |= nSRST;
1213 }
1214 else
1215 {
1216 high_output |= nSRSTnOE;
1217 high_output &= ~nSRST;
1218 }
1219
1220 /* initialize high port */
1221 buf[0] = 0x82; /* command "set data bits high byte" */
1222 buf[1] = high_output; /* value */
1223 buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
1224 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1225
1226 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1227 {
1228 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1229 return ERROR_JTAG_INIT_FAILED;
1230 }
1231
1232 return ERROR_OK;
1233 }
1234
1235 int olimex_jtag_init(void)
1236 {
1237 u8 buf[3];
1238 u32 bytes_written;
1239
1240 low_output = 0x08;
1241 low_direction = 0x1b;
1242
1243 /* initialize low byte for jtag */
1244 buf[0] = 0x80; /* command "set data bits low byte" */
1245 buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
1246 buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
1247 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1248
1249 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1250 {
1251 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1252 return ERROR_JTAG_INIT_FAILED;
1253 }
1254
1255 nTRST = 0x01;
1256 nTRSTnOE = 0x4;
1257 nSRST = 0x02;
1258 nSRSTnOE = 0x00; /* no output enable for nSRST */
1259
1260 high_output = 0x0;
1261 high_direction = 0x0f;
1262
1263 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
1264 {
1265 high_output |= nTRSTnOE;
1266 high_output &= ~nTRST;
1267 }
1268 else
1269 {
1270 high_output &= ~nTRSTnOE;
1271 high_output |= nTRST;
1272 }
1273
1274 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
1275 {
1276 ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD");
1277 }
1278 else
1279 {
1280 high_output &= ~nSRST;
1281 }
1282
1283 /* turn red LED on */
1284 high_output |= 0x08;
1285
1286 /* initialize high port */
1287 buf[0] = 0x82; /* command "set data bits high byte" */
1288 buf[1] = high_output; /* value */
1289 buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
1290 DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
1291
1292 if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
1293 {
1294 ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
1295 return ERROR_JTAG_INIT_FAILED;
1296 }
1297
1298 return ERROR_OK;
1299 }
1300
1301 void olimex_jtag_blink(void)
1302 {
1303 /* Olimex ARM-USB-OCD has a LED connected to ACBUS3
1304 * ACBUS3 is bit 3 of the GPIOH port
1305 */
1306 if (high_output & 0x08)
1307 {
1308 /* set port pin high */
1309 high_output &= 0x07;
1310 }
1311 else
1312 {
1313 /* set port pin low */
1314 high_output |= 0x08;
1315 }
1316
1317 BUFFER_ADD = 0x82;
1318 BUFFER_ADD = high_output;
1319 BUFFER_ADD = high_direction;
1320 }
1321
1322 int ft2232_quit(void)
1323 {
1324 #if BUILD_FT2232_FTD2XX == 1
1325 FT_STATUS status;
1326
1327 status = FT_Close(ftdih);
1328 #elif BUILD_FT2232_LIBFTDI == 1
1329 ftdi_disable_bitbang(&ftdic);
1330
1331 ftdi_usb_close(&ftdic);
1332
1333 ftdi_deinit(&ftdic);
1334 #endif
1335
1336 free(ft2232_buffer);
1337
1338 return ERROR_OK;
1339 }
1340
1341 int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1342 {
1343 if (argc == 1)
1344 {
1345 ft2232_device_desc = strdup(args[0]);
1346 }
1347 else
1348 {
1349 ERROR("expected exactly one argument to ft2232_device_desc <description>");
1350 }
1351
1352 return ERROR_OK;
1353 }
1354
1355 int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1356 {
1357 if (argc == 0)
1358 return ERROR_OK;
1359
1360 ft2232_layout = malloc(strlen(args[0]) + 1);
1361 strcpy(ft2232_layout, args[0]);
1362
1363 return ERROR_OK;
1364 }
1365
1366 int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1367 {
1368 if (argc >= 2)
1369 {
1370 ft2232_vid = strtol(args[0], NULL, 0);
1371 ft2232_pid = strtol(args[1], NULL, 0);
1372 }
1373 else
1374 {
1375 WARNING("incomplete ft2232_vid_pid configuration directive");
1376 }
1377
1378 return ERROR_OK;
1379 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)