build: cleanup src/jtag/drivers directory
[openocd.git] / src / jtag / drivers / usb_blaster.c
1 /***************************************************************************
2 * Driver for USB-JTAG, Altera USB-Blaster and compatibles *
3 * Original code from Kolja Waschk's USB-JTAG project *
4 * (http://www.ixo.de/info/usb_jtag/). *
5 * Some updates by Anthony Liu (2006). *
6 * Minor updates and cleanup by Catalin Patulea (2009). *
7 * Speed updates by Ali Lown (2011). *
8 * *
9 * Copyright (C) 2011 Ali Lown *
10 * ali@lown.me.uk *
11 * *
12 * Copyright (C) 2009 Catalin Patulea *
13 * cat@vv.carleton.ca *
14 * *
15 * Copyright (C) 2006 Kolja Waschk *
16 * usbjtag@ixo.de *
17 * *
18 * Based on ft2232.c and bitbang.c, *
19 * Copyright (C) 2004,2006 by Dominic Rath *
20 * *
21 * This program is free software; you can redistribute it and/or modify *
22 * it under the terms of the GNU General Public License as published by *
23 * the Free Software Foundation; either version 2 of the License, or *
24 * (at your option) any later version. *
25 * *
26 * This program is distributed in the hope that it will be useful, *
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
29 * GNU General Public License for more details. *
30 * *
31 * You should have received a copy of the GNU General Public License *
32 * along with this program; if not, write to the *
33 * Free Software Foundation, Inc., *
34 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
35 ***************************************************************************/
36
37 /*
38 * The following information is originally from Kolja Waschk's USB-JTAG,
39 * where it was obtained by reverse engineering an Altera USB-Blaster.
40 * See http://www.ixo.de/info/usb_jtag/ for USB-Blaster block diagram and
41 * usb_jtag-20080705-1200.zip#usb_jtag/host/openocd for protocol.
42 *
43 * The same information is also on the UrJTAG mediawiki, with some additional
44 * notes on bits marked as "unknown" by usb_jtag.
45 * (http://sourceforge.net/apps/mediawiki/urjtag/index.php?
46 * title=Cable_Altera_USB-Blaster)
47 *
48 * USB-JTAG, Altera USB-Blaster and compatibles are typically implemented as
49 * an FTDIChip FT245 followed by a CPLD which handles a two-mode protocol:
50 *
51 * _________
52 * | |
53 * | AT93C46 |
54 * |_________|
55 * __|__________ _________
56 * | | | |
57 * USB__| FTDI 245BM |__| EPM7064 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK)
58 * |_____________| |_________|
59 * __|__________ _|___________
60 * | | | |
61 * | 6 MHz XTAL | | 24 MHz Osc. |
62 * |_____________| |_____________|
63 *
64 * Protocol details are given in the code below.
65 *
66 * It is also possible to emulate this configuration using a single-chip USB
67 * controller like the Cypress FX2 (again, see usb_jtag for details).
68 */
69 #ifdef HAVE_CONFIG_H
70 #include "config.h"
71 #endif
72
73 #if IS_CYGWIN == 1
74 #include "windows.h"
75 #undef LOG_ERROR
76 #endif
77
78 /* project specific includes */
79 #include <jtag/interface.h>
80 #include <jtag/commands.h>
81 #include <helper/time_support.h>
82
83 /* system includes */
84 #include <string.h>
85 #include <stdlib.h>
86 #include <unistd.h>
87
88 #include "bitbang.h"
89
90 #if (BUILD_USB_BLASTER_FTD2XX == 1 && BUILD_USB_BLASTER_LIBFTDI == 1)
91 #error "BUILD_USB_BLASTER_FTD2XX && BUILD_USB_BLASTER_LIBFTDI "
92 "are mutually exclusive"
93 #elif (BUILD_USB_BLASTER_FTD2XX != 1 && BUILD_USB_BLASTER_LIBFTDI != 1)
94 #error "BUILD_USB_BLASTER_FTD2XX || BUILD_USB_BLASTER_LIBFTDI must be chosen"
95 #endif
96
97 /* USB_BLASTER access library includes */
98 #if BUILD_USB_BLASTER_FTD2XX == 1
99 #include <ftd2xx.h>
100 #include "ftd2xx_common.h"
101 #elif BUILD_USB_BLASTER_LIBFTDI == 1
102 #include <ftdi.h>
103 #endif
104
105 #include <sys/time.h>
106 #include <time.h>
107
108 static char *usb_blaster_device_desc;
109 static uint16_t usb_blaster_vid = 0x09fb; /* Altera */
110 static uint16_t usb_blaster_pid = 0x6001; /* USB-Blaster */
111
112 /* last output byte in simple bit banging (legacy) mode */
113 static uint8_t out_value;
114 /* global output buffer for bit banging */
115 #define BUF_LEN 64 /* Size of EP1 */
116 static uint8_t out_buffer[BUF_LEN];
117 static uint16_t out_count;
118
119 #if BUILD_USB_BLASTER_FTD2XX == 1
120 static FT_HANDLE ftdih;
121 #elif BUILD_USB_BLASTER_LIBFTDI == 1
122 static struct ftdi_context ftdic;
123 #endif
124
125 static int usb_blaster_buf_write(
126 uint8_t *buf, int size, uint32_t *bytes_written)
127 {
128 #if BUILD_USB_BLASTER_FTD2XX == 1
129 FT_STATUS status;
130 DWORD dw_bytes_written;
131
132 #ifdef _DEBUG_JTAG_IO_
133 LOG_DEBUG("usb_blaster_buf_write %02X (%d)", buf[0], size);
134 #endif
135 status = FT_Write(ftdih, buf, size, &dw_bytes_written);
136 if (status != FT_OK) {
137 *bytes_written = dw_bytes_written;
138 LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(status));
139 return ERROR_JTAG_DEVICE_ERROR;
140 }
141 *bytes_written = dw_bytes_written;
142 return ERROR_OK;
143 #elif BUILD_USB_BLASTER_LIBFTDI == 1
144 int retval;
145 #ifdef _DEBUG_JTAG_IO_
146 LOG_DEBUG("usb_blaster_buf_write %02X (%d)", buf[0], size);
147 #endif
148 retval = ftdi_write_data(&ftdic, buf, size);
149 if (retval < 0) {
150 *bytes_written = 0;
151 LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic));
152 return ERROR_JTAG_DEVICE_ERROR;
153 }
154 *bytes_written = retval;
155 return ERROR_OK;
156 #endif
157 }
158
159 static int usb_blaster_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read)
160 {
161 #if BUILD_USB_BLASTER_FTD2XX == 1
162 DWORD dw_bytes_read;
163 FT_STATUS status;
164
165 status = FT_Read(ftdih, buf, size, &dw_bytes_read);
166 if (status != FT_OK) {
167 *bytes_read = dw_bytes_read;
168 LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(status));
169 return ERROR_JTAG_DEVICE_ERROR;
170 }
171 #ifdef _DEBUG_JTAG_IO_
172 LOG_DEBUG("usb_blaster_buf_read %02X (%" PRIu32 ")", buf[0], dw_bytes_read);
173 #endif
174 *bytes_read = dw_bytes_read;
175 return ERROR_OK;
176
177 #elif BUILD_USB_BLASTER_LIBFTDI == 1
178 int retval;
179 int timeout = 100;
180
181 *bytes_read = 0;
182 while ((*bytes_read < size) && timeout--) {
183 retval = ftdi_read_data(&ftdic, buf + *bytes_read,
184 size - *bytes_read);
185 if (retval < 0) {
186 *bytes_read = 0;
187 LOG_ERROR("ftdi_read_data: %s",
188 ftdi_get_error_string(&ftdic));
189 return ERROR_JTAG_DEVICE_ERROR;
190 }
191 *bytes_read += retval;
192 }
193 #ifdef _DEBUG_JTAG_IO_
194 LOG_DEBUG("usb_blaster_buf_read %02X (%d)", buf[0], *bytes_read);
195 #endif
196 return ERROR_OK;
197 #endif
198 }
199
200 /* The following code doesn't fully utilize the possibilities of the
201 * USB-Blaster. It only buffers data up to the maximum packet size of 64 bytes.
202 *
203 * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 data
204 * bits (bidirectional) in a single USB packet. A header byte has to be sent as
205 * the first byte in a packet with the following meaning:
206 *
207 * Bit 7 (0x80): Must be set to indicate byte-shift mode.
208 * Bit 6 (0x40): If set, the USB-Blaster will also read data, not just write.
209 * Bit 5..0: Define the number N of following bytes
210 *
211 * All N following bytes will then be clocked out serially on TDI. If Bit 6 was
212 * set, it will afterwards return N bytes with TDO data read while clocking out
213 * the TDI data. LSB of the first byte after the header byte will appear first
214 * on TDI.
215 */
216
217 /* Simple bit banging mode:
218 *
219 * Bit 7 (0x80): Must be zero (see byte-shift mode above)
220 * Bit 6 (0x40): If set, you will receive a byte indicating the state of TDO
221 * in return.
222 * Bit 5 (0x20): Output Enable/LED.
223 * Bit 4 (0x10): TDI Output.
224 * Bit 3 (0x08): nCS Output (not used in JTAG mode).
225 * Bit 2 (0x04): nCE Output (not used in JTAG mode).
226 * Bit 1 (0x02): TMS Output.
227 * Bit 0 (0x01): TCK Output.
228 *
229 * For transmitting a single data bit, you need to write two bytes. Up to 64
230 * bytes can be combined in a single USB packet.
231 * It isn't possible to read a data without transmitting data.
232 */
233
234 #define TCK (1 << 0)
235 #define TMS (1 << 1)
236 #define NCE (1 << 2)
237 #define NCS (1 << 3)
238 #define TDI (1 << 4)
239 #define LED (1 << 5)
240 #define READ (1 << 6)
241 #define SHMODE (1 << 7)
242 #define OTHERS ((1 << 2) | (1 << 3) | (1 << 5))
243
244 #define READ_TDO (1 << 0)
245
246 static void usb_blaster_write_databuffer(uint8_t *buf, uint16_t len)
247 {
248 uint32_t bytes_written;
249 usb_blaster_buf_write(buf, len, &bytes_written);
250 out_count = 0;
251 #ifdef _DEBUG_JTAG_IO_
252 LOG_DEBUG("---- WROTE %d", bytes_written);
253 #endif
254 }
255
256 static void usb_blaster_addtowritebuffer(uint8_t value, bool forcewrite)
257 {
258 out_buffer[out_count] = value;
259 out_count += 1;
260 if (out_count == BUF_LEN || forcewrite)
261 usb_blaster_write_databuffer(out_buffer, out_count);
262 }
263
264 static int usb_blaster_read_data(void)
265 {
266 int status;
267 uint8_t buf[1];
268 uint32_t bytes_read;
269
270 if (out_count > 0)
271 usb_blaster_write_databuffer(out_buffer, out_count);
272
273 out_value |= READ;
274 usb_blaster_addtowritebuffer(out_value, true);
275 out_value &= ~READ;
276
277 status = usb_blaster_buf_read(buf, 1, &bytes_read);
278 if (status < 0)
279 return 0;
280
281 return !!(buf[0] & READ_TDO);
282 }
283
284 static void usb_blaster_write(int tck, int tms, int tdi)
285 {
286 #ifdef _DEBUG_JTAG_IO_
287 LOG_DEBUG("---- usb_blaster_write(%d,%d,%d)", tck, tms, tdi);
288 #endif
289 out_value &= ~(TCK | TMS | TDI);
290 if (tck)
291 out_value |= TCK;
292 if (tms)
293 out_value |= TMS;
294 if (tdi)
295 out_value |= TDI;
296
297 usb_blaster_addtowritebuffer(out_value, false);
298 }
299
300 static int usb_blaster_speed(int speed)
301 {
302 #if BUILD_USB_BLASTER_FTD2XX == 1
303 LOG_DEBUG("TODO: usb_blaster_speed() isn't implemented for libftd2xx!");
304 #elif BUILD_USB_BLASTER_LIBFTDI == 1
305 LOG_DEBUG("TODO: usb_blaster_speed() isn't optimally implemented!");
306
307 /* TODO: libftdi's ftdi_set_baudrate chokes on high rates, use lowlevel
308 * usb function instead! And additionally allow user to throttle.
309 */
310 if (ftdi_set_baudrate(&ftdic, 3000000 / 4) < 0) {
311 LOG_ERROR("Can't set baud rate to max: %s",
312 ftdi_get_error_string(&ftdic));
313 return ERROR_JTAG_DEVICE_ERROR;
314 }
315 ;
316 #endif
317
318 return ERROR_OK;
319 }
320
321 static void usb_blaster_reset(int trst, int srst)
322 {
323 LOG_DEBUG("TODO: usb_blaster_reset(%d,%d) isn't implemented!",
324 trst, srst);
325 }
326
327 static void usb_blaster_blink(int state)
328 {
329 out_value = 0x00;
330 if (state)
331 out_value |= LED;
332
333 usb_blaster_addtowritebuffer(out_value, true);
334 }
335
336 static struct bitbang_interface usb_blaster_bitbang = {
337 .read = usb_blaster_read_data,
338 .write = usb_blaster_write,
339 .reset = usb_blaster_reset,
340 .blink = usb_blaster_blink,
341 };
342
343 static int usb_blaster_init(void)
344 {
345 uint8_t latency_timer;
346
347 #if BUILD_USB_BLASTER_FTD2XX == 1
348 FT_STATUS status;
349 #endif
350
351 #if BUILD_USB_BLASTER_FTD2XX == 1
352 LOG_DEBUG("'usb_blaster' interface using FTD2XX");
353 #elif BUILD_USB_BLASTER_LIBFTDI == 1
354 LOG_DEBUG("'usb_blaster' interface using libftdi");
355 #endif
356
357 #if BUILD_USB_BLASTER_FTD2XX == 1
358 /* Open by device description */
359 if (usb_blaster_device_desc == NULL) {
360 LOG_WARNING("no usb_blaster device description specified, "
361 "using default 'USB-Blaster'");
362 usb_blaster_device_desc = "USB-Blaster";
363 }
364
365 #if IS_WIN32 == 0
366 /* Add non-standard Vid/Pid to the linux driver */
367 status = FT_SetVIDPID(usb_blaster_vid, usb_blaster_pid);
368 if (status != FT_OK) {
369 LOG_WARNING("couldn't add %4.4x:%4.4x",
370 usb_blaster_vid, usb_blaster_pid);
371 }
372 #endif
373
374 status = FT_OpenEx(usb_blaster_device_desc, FT_OPEN_BY_DESCRIPTION,
375 &ftdih);
376 if (status != FT_OK) {
377 DWORD num_devices;
378
379 LOG_ERROR("unable to open ftdi device: %s",
380 ftd2xx_status_string(status));
381 status = FT_ListDevices(&num_devices, NULL,
382 FT_LIST_NUMBER_ONLY);
383 if (status == FT_OK) {
384 char **desc_array = malloc(sizeof(char *)
385 * (num_devices + 1));
386 unsigned int i;
387
388 for (i = 0; i < num_devices; i++)
389 desc_array[i] = malloc(64);
390 desc_array[num_devices] = NULL;
391
392 status = FT_ListDevices(desc_array, &num_devices,
393 FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
394
395 if (status == FT_OK) {
396 LOG_ERROR("ListDevices: %" PRIu32, (uint32_t)num_devices);
397 for (i = 0; i < num_devices; i++)
398 LOG_ERROR("%i: %s", i, desc_array[i]);
399 }
400
401 for (i = 0; i < num_devices; i++)
402 free(desc_array[i]);
403 free(desc_array);
404 } else
405 printf("ListDevices: NONE\n");
406 return ERROR_JTAG_INIT_FAILED;
407 }
408
409 status = FT_SetLatencyTimer(ftdih, 2);
410 if (status != FT_OK) {
411 LOG_ERROR("unable to set latency timer: %s",
412 ftd2xx_status_string(status));
413 return ERROR_JTAG_INIT_FAILED;
414 }
415
416 status = FT_GetLatencyTimer(ftdih, &latency_timer);
417 if (status != FT_OK) {
418 LOG_ERROR("unable to get latency timer: %s",
419 ftd2xx_status_string(status));
420 return ERROR_JTAG_INIT_FAILED;
421 }
422 LOG_DEBUG("current latency timer: %i", latency_timer);
423
424 status = FT_SetBitMode(ftdih, 0x00, 0);
425 if (status != FT_OK) {
426 LOG_ERROR("unable to disable bit i/o mode: %s",
427 ftd2xx_status_string(status));
428 return ERROR_JTAG_INIT_FAILED;
429 }
430 #elif BUILD_USB_BLASTER_LIBFTDI == 1
431 if (ftdi_init(&ftdic) < 0)
432 return ERROR_JTAG_INIT_FAILED;
433
434 /* context, vendor id, product id */
435 if (ftdi_usb_open(&ftdic, usb_blaster_vid, usb_blaster_pid) < 0) {
436 LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str);
437 return ERROR_JTAG_INIT_FAILED;
438 }
439
440 if (ftdi_usb_reset(&ftdic) < 0) {
441 LOG_ERROR("unable to reset ftdi device");
442 return ERROR_JTAG_INIT_FAILED;
443 }
444
445 if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
446 LOG_ERROR("unable to set latency timer");
447 return ERROR_JTAG_INIT_FAILED;
448 }
449
450 if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) {
451 LOG_ERROR("unable to get latency timer");
452 return ERROR_JTAG_INIT_FAILED;
453 }
454 LOG_DEBUG("current latency timer: %u", latency_timer);
455
456 ftdi_disable_bitbang(&ftdic);
457 #endif
458
459 bitbang_interface = &usb_blaster_bitbang;
460
461 #if 0
462 #if BUILD_USB_BLASTER_FTD2XX == 1
463 status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX);
464 if (status != FT_OK) {
465 LOG_ERROR("error purging ftd2xx device: %i", status);
466 return ERROR_JTAG_INIT_FAILED;
467 }
468 #elif BUILD_USB_BLASTER_LIBFTDI == 1
469 if (ftdi_usb_purge_buffers(&ftdic) < 0) {
470 LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
471 return ERROR_JTAG_INIT_FAILED;
472 }
473 #endif
474 #endif
475
476 return ERROR_OK;
477 }
478
479 static int usb_blaster_quit(void)
480 {
481 if (out_count > 0)
482 usb_blaster_write_databuffer(out_buffer, out_count);
483
484 #if BUILD_USB_BLASTER_FTD2XX == 1
485 FT_STATUS status;
486
487 status = FT_Close(ftdih);
488 #elif BUILD_USB_BLASTER_LIBFTDI == 1
489 ftdi_usb_close(&ftdic);
490 ftdi_deinit(&ftdic);
491 #endif
492
493 return ERROR_OK;
494 }
495
496 COMMAND_HANDLER(usb_blaster_handle_device_desc_command)
497 {
498 if (CMD_ARGC == 1)
499 usb_blaster_device_desc = strdup(CMD_ARGV[0]);
500 else
501 LOG_ERROR("require exactly one argument to "
502 "usb_blaster_device_desc <description>");
503
504 return ERROR_OK;
505 }
506
507 COMMAND_HANDLER(usb_blaster_handle_vid_pid_command)
508 {
509 if (CMD_ARGC > 2) {
510 LOG_WARNING("ignoring extra IDs in usb_blaster_vid_pid "
511 "(maximum is 1 pair)");
512 CMD_ARGC = 2;
513 }
514 if (CMD_ARGC == 2) {
515 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], usb_blaster_vid);
516 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], usb_blaster_pid);
517 } else
518 LOG_WARNING("incomplete usb_blaster_vid_pid configuration");
519
520 return ERROR_OK;
521 }
522
523 COMMAND_HANDLER(usb_blaster_handle_pin_command)
524 {
525 if (CMD_ARGC == 2) {
526 const char *const pin_name = CMD_ARGV[0];
527 uint8_t mask;
528 unsigned int state;
529
530 if (!strcmp(pin_name, "pin6"))
531 mask = NCE;
532 else if (!strcmp(pin_name, "pin8"))
533 mask = NCS;
534 else {
535 LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"",
536 CMD_NAME);
537 return ERROR_COMMAND_SYNTAX_ERROR;
538 }
539
540 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], state);
541 if (state == 0) {
542 out_value &= ~mask;
543 usb_blaster_addtowritebuffer(out_value, true);
544 } else if (state == 1) {
545 out_value |= mask;
546 usb_blaster_addtowritebuffer(out_value, true);
547 } else {
548 LOG_ERROR("%s: pin state must be 0 or 1", CMD_NAME);
549 return ERROR_COMMAND_SYNTAX_ERROR;
550 }
551
552 return ERROR_OK;
553 } else {
554 LOG_ERROR("%s takes exactly two arguments", CMD_NAME);
555 return ERROR_COMMAND_SYNTAX_ERROR;
556 }
557 }
558
559 static const struct command_registration usb_blaster_command_handlers[] = {
560 {
561 .name = "usb_blaster_device_desc",
562 .handler = usb_blaster_handle_device_desc_command,
563 .mode = COMMAND_CONFIG,
564 .help = "set the USB device description of the USB-Blaster",
565 .usage = "description-string",
566 },
567 {
568 .name = "usb_blaster_vid_pid",
569 .handler = usb_blaster_handle_vid_pid_command,
570 .mode = COMMAND_CONFIG,
571 .help = "the vendor ID and product ID of the USB-Blaster",
572 .usage = "vid pid",
573 },
574 {
575 .name = "usb_blaster",
576 .handler = usb_blaster_handle_pin_command,
577 .mode = COMMAND_ANY,
578 .help = "set pin state for the unused GPIO pins",
579 .usage = "(pin6|pin8) (0|1)",
580 },
581 COMMAND_REGISTRATION_DONE
582 };
583
584 struct jtag_interface usb_blaster_interface = {
585 .name = "usb_blaster",
586 .commands = usb_blaster_command_handlers,
587 .supported = DEBUG_CAP_TMS_SEQ,
588
589 .execute_queue = bitbang_execute_queue,
590
591 .speed = usb_blaster_speed,
592 .init = usb_blaster_init,
593 .quit = usb_blaster_quit,
594 };

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)