1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * Bitbang driver for Linux GPIO descriptors through libgpiod
4 * Copyright (C) 2020 Antonio Borneo <borneo.antonio@gmail.com>
6 * Largely based on sysfsgpio driver
7 * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au
8 * Copyright (C) 2014 by Jean-Christian de Rivaz <jc@eclis.ch>
9 * Copyright (C) 2014 by Paul Fertser <fercerpav@gmail.com>
17 #include <jtag/interface.h>
18 #include <transport/transport.h>
21 /* gpio numbers for each gpio. Negative values are invalid */
22 static int tck_gpio
= -1;
23 static int tms_gpio
= -1;
24 static int tdi_gpio
= -1;
25 static int tdo_gpio
= -1;
26 static int trst_gpio
= -1;
27 static int srst_gpio
= -1;
28 static int swclk_gpio
= -1;
29 static int swdio_gpio
= -1;
30 static int led_gpio
= -1;
31 static int gpiochip
= -1;
32 static int tck_gpiochip
= -1;
33 static int tms_gpiochip
= -1;
34 static int tdi_gpiochip
= -1;
35 static int tdo_gpiochip
= -1;
36 static int trst_gpiochip
= -1;
37 static int srst_gpiochip
= -1;
38 static int swclk_gpiochip
= -1;
39 static int swdio_gpiochip
= -1;
40 static int led_gpiochip
= -1;
42 static struct gpiod_chip
*gpiod_chip_tck
;
43 static struct gpiod_chip
*gpiod_chip_tms
;
44 static struct gpiod_chip
*gpiod_chip_tdi
;
45 static struct gpiod_chip
*gpiod_chip_tdo
;
46 static struct gpiod_chip
*gpiod_chip_trst
;
47 static struct gpiod_chip
*gpiod_chip_srst
;
48 static struct gpiod_chip
*gpiod_chip_swclk
;
49 static struct gpiod_chip
*gpiod_chip_swdio
;
50 static struct gpiod_chip
*gpiod_chip_led
;
52 static struct gpiod_line
*gpiod_tck
;
53 static struct gpiod_line
*gpiod_tms
;
54 static struct gpiod_line
*gpiod_tdi
;
55 static struct gpiod_line
*gpiod_tdo
;
56 static struct gpiod_line
*gpiod_trst
;
57 static struct gpiod_line
*gpiod_swclk
;
58 static struct gpiod_line
*gpiod_swdio
;
59 static struct gpiod_line
*gpiod_srst
;
60 static struct gpiod_line
*gpiod_led
;
62 static int last_swclk
;
63 static int last_swdio
;
64 static bool last_stored
;
65 static bool swdio_input
;
67 /* Bitbang interface read of TDO */
68 static bb_value_t
linuxgpiod_read(void)
72 retval
= gpiod_line_get_value(gpiod_tdo
);
74 LOG_WARNING("reading tdo failed");
78 return retval
? BB_HIGH
: BB_LOW
;
82 * Bitbang interface write of TCK, TMS, TDI
84 * Seeing as this is the only function where the outputs are changed,
85 * we can cache the old value to avoid needlessly writing it.
87 static int linuxgpiod_write(int tck
, int tms
, int tdi
)
93 static int first_time
;
104 if (tdi
!= last_tdi
) {
105 retval
= gpiod_line_set_value(gpiod_tdi
, tdi
);
107 LOG_WARNING("writing tdi failed");
110 if (tms
!= last_tms
) {
111 retval
= gpiod_line_set_value(gpiod_tms
, tms
);
113 LOG_WARNING("writing tms failed");
117 if (tck
!= last_tck
) {
118 retval
= gpiod_line_set_value(gpiod_tck
, tck
);
120 LOG_WARNING("writing tck failed");
130 static int linuxgpiod_swdio_read(void)
134 retval
= gpiod_line_get_value(gpiod_swdio
);
136 LOG_WARNING("Fail read swdio");
143 static void linuxgpiod_swdio_drive(bool is_output
)
148 * FIXME: change direction requires release and re-require the line
149 * https://stackoverflow.com/questions/58735140/
150 * this would change in future libgpiod
152 gpiod_line_release(gpiod_swdio
);
155 retval
= gpiod_line_request_output(gpiod_swdio
, "OpenOCD", 1);
157 LOG_WARNING("Fail request_output line swdio");
159 retval
= gpiod_line_request_input(gpiod_swdio
, "OpenOCD");
161 LOG_WARNING("Fail request_input line swdio");
165 swdio_input
= !is_output
;
168 static int linuxgpiod_swd_write(int swclk
, int swdio
)
173 if (!last_stored
|| (swdio
!= last_swdio
)) {
174 retval
= gpiod_line_set_value(gpiod_swdio
, swdio
);
176 LOG_WARNING("Fail set swdio");
180 /* write swclk last */
181 if (!last_stored
|| (swclk
!= last_swclk
)) {
182 retval
= gpiod_line_set_value(gpiod_swclk
, swclk
);
184 LOG_WARNING("Fail set swclk");
194 static int linuxgpiod_blink(int on
)
201 retval
= gpiod_line_set_value(gpiod_led
, on
);
203 LOG_WARNING("Fail set led");
207 static struct bitbang_interface linuxgpiod_bitbang
= {
208 .read
= linuxgpiod_read
,
209 .write
= linuxgpiod_write
,
210 .swdio_read
= linuxgpiod_swdio_read
,
211 .swdio_drive
= linuxgpiod_swdio_drive
,
212 .swd_write
= linuxgpiod_swd_write
,
213 .blink
= linuxgpiod_blink
,
217 * Bitbang interface to manipulate reset lines SRST and TRST
219 * (1) assert or (0) deassert reset lines
221 static int linuxgpiod_reset(int trst
, int srst
)
223 int retval1
= 0, retval2
= 0;
225 LOG_DEBUG("linuxgpiod_reset");
227 /* assume active low */
229 retval1
= gpiod_line_set_value(gpiod_srst
, srst
? 0 : 1);
231 LOG_WARNING("set srst value failed");
234 /* assume active low */
236 retval2
= gpiod_line_set_value(gpiod_trst
, trst
? 0 : 1);
238 LOG_WARNING("set trst value failed");
241 return ((retval1
< 0) || (retval2
< 0)) ? ERROR_FAIL
: ERROR_OK
;
245 * Helper function to determine if gpio number is valid
247 * Assume here that there will be less than 10000 gpios per gpiochip
249 static bool is_gpio_valid(int gpio
)
251 return gpio
>= 0 && gpio
< 10000;
254 static bool linuxgpiod_jtag_mode_possible(void)
256 if (!is_gpio_valid(tck_gpio
))
258 if (!is_gpio_valid(tms_gpio
))
260 if (!is_gpio_valid(tdi_gpio
))
262 if (!is_gpio_valid(tdo_gpio
))
267 static bool linuxgpiod_swd_mode_possible(void)
269 if (!is_gpio_valid(swclk_gpio
))
271 if (!is_gpio_valid(swdio_gpio
))
276 static inline void helper_release(struct gpiod_line
*line
)
279 gpiod_line_release(line
);
282 static int linuxgpiod_quit(void)
284 helper_release(gpiod_led
);
285 helper_release(gpiod_srst
);
286 helper_release(gpiod_swdio
);
287 helper_release(gpiod_swclk
);
288 helper_release(gpiod_trst
);
289 helper_release(gpiod_tms
);
290 helper_release(gpiod_tck
);
291 helper_release(gpiod_tdi
);
292 helper_release(gpiod_tdo
);
294 if (gpiod_chip_led
!= NULL
)
295 gpiod_chip_close(gpiod_chip_led
);
296 if (gpiod_chip_srst
!= NULL
)
297 gpiod_chip_close(gpiod_chip_srst
);
298 if (gpiod_chip_swdio
!= NULL
)
299 gpiod_chip_close(gpiod_chip_swdio
);
300 if (gpiod_chip_swclk
!= NULL
)
301 gpiod_chip_close(gpiod_chip_swclk
);
302 if (gpiod_chip_trst
!= NULL
)
303 gpiod_chip_close(gpiod_chip_trst
);
304 if (gpiod_chip_tms
!= NULL
)
305 gpiod_chip_close(gpiod_chip_tms
);
306 if (gpiod_chip_tck
!= NULL
)
307 gpiod_chip_close(gpiod_chip_tck
);
308 if (gpiod_chip_tdi
!= NULL
)
309 gpiod_chip_close(gpiod_chip_tdi
);
310 if (gpiod_chip_tdo
!= NULL
)
311 gpiod_chip_close(gpiod_chip_tdo
);
316 static struct gpiod_line
*helper_get_line(const char *label
,
317 struct gpiod_chip
*gpiod_chip
, unsigned int offset
,
318 int val
, int dir
, int flags
)
320 struct gpiod_line
*line
;
323 line
= gpiod_chip_get_line(gpiod_chip
, offset
);
325 LOG_ERROR("Error get line %s", label
);
329 struct gpiod_line_request_config config
= {
330 .consumer
= "OpenOCD",
335 retval
= gpiod_line_request(line
, &config
, val
);
337 LOG_ERROR("Error requesting gpio line %s", label
);
344 static struct gpiod_line
*helper_get_input_line(const char *label
,
345 struct gpiod_chip
*gpiod_chip
, unsigned int offset
)
347 return helper_get_line(label
, gpiod_chip
, offset
, 0,
348 GPIOD_LINE_REQUEST_DIRECTION_INPUT
, 0);
351 static struct gpiod_line
*helper_get_output_line(const char *label
,
352 struct gpiod_chip
*gpiod_chip
, unsigned int offset
, int val
)
354 return helper_get_line(label
, gpiod_chip
, offset
, val
,
355 GPIOD_LINE_REQUEST_DIRECTION_OUTPUT
, 0);
358 static struct gpiod_line
*helper_get_open_drain_output_line(const char *label
,
359 struct gpiod_chip
*gpiod_chip
, unsigned int offset
, int val
)
361 return helper_get_line(label
, gpiod_chip
, offset
, val
,
362 GPIOD_LINE_REQUEST_DIRECTION_OUTPUT
, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN
);
365 static int linuxgpiod_init(void)
367 LOG_INFO("Linux GPIOD JTAG/SWD bitbang driver");
369 bitbang_interface
= &linuxgpiod_bitbang
;
372 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
373 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
374 * For SWD, SWCLK and SWDIO are configures as output high.
377 if (transport_is_jtag()) {
378 if (!linuxgpiod_jtag_mode_possible()) {
379 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
383 gpiod_chip_tdo
= gpiod_chip_open_by_number(tdo_gpiochip
);
384 if (!gpiod_chip_tdo
) {
385 LOG_ERROR("Cannot open LinuxGPIOD tdo_gpiochip %d", tdo_gpiochip
);
388 gpiod_chip_tdi
= gpiod_chip_open_by_number(tdi_gpiochip
);
389 if (!gpiod_chip_tdi
) {
390 LOG_ERROR("Cannot open LinuxGPIOD tdi_gpiochip %d", tdi_gpiochip
);
393 gpiod_chip_tck
= gpiod_chip_open_by_number(tck_gpiochip
);
394 if (!gpiod_chip_tck
) {
395 LOG_ERROR("Cannot open LinuxGPIOD tck_gpiochip %d", tck_gpiochip
);
398 gpiod_chip_tms
= gpiod_chip_open_by_number(tms_gpiochip
);
399 if (!gpiod_chip_tms
) {
400 LOG_ERROR("Cannot open LinuxGPIOD tms_gpiochip %d", tms_gpiochip
);
404 gpiod_tdo
= helper_get_input_line("tdo", gpiod_chip_tdo
, tdo_gpio
);
408 gpiod_tdi
= helper_get_output_line("tdi", gpiod_chip_tdi
, tdi_gpio
, 0);
412 gpiod_tck
= helper_get_output_line("tck", gpiod_chip_tck
, tck_gpio
, 0);
416 gpiod_tms
= helper_get_output_line("tms", gpiod_chip_tms
, tms_gpio
, 1);
420 if (is_gpio_valid(trst_gpio
)) {
421 gpiod_chip_trst
= gpiod_chip_open_by_number(trst_gpiochip
);
422 if (!gpiod_chip_trst
) {
423 LOG_ERROR("Cannot open LinuxGPIOD trst_gpiochip %d", trst_gpiochip
);
427 if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN
)
428 gpiod_trst
= helper_get_open_drain_output_line("trst", gpiod_chip_trst
, trst_gpio
, 1);
430 gpiod_trst
= helper_get_output_line("trst", gpiod_chip_trst
, trst_gpio
, 1);
437 if (transport_is_swd()) {
438 if (!linuxgpiod_swd_mode_possible()) {
439 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
443 gpiod_chip_swclk
= gpiod_chip_open_by_number(swclk_gpiochip
);
444 if (!gpiod_chip_swclk
) {
445 LOG_ERROR("Cannot open LinuxGPIOD swclk_gpiochip %d", swclk_gpiochip
);
448 gpiod_chip_swdio
= gpiod_chip_open_by_number(swdio_gpiochip
);
449 if (!gpiod_chip_swdio
) {
450 LOG_ERROR("Cannot open LinuxGPIOD swdio_gpiochip %d", swdio_gpiochip
);
454 gpiod_swclk
= helper_get_output_line("swclk", gpiod_chip_swclk
, swclk_gpio
, 1);
458 gpiod_swdio
= helper_get_output_line("swdio", gpiod_chip_swdio
, swdio_gpio
, 1);
463 if (is_gpio_valid(srst_gpio
)) {
464 gpiod_chip_srst
= gpiod_chip_open_by_number(srst_gpiochip
);
465 if (!gpiod_chip_srst
) {
466 LOG_ERROR("Cannot open LinuxGPIOD srst_gpiochip %d", srst_gpiochip
);
470 if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL
)
471 gpiod_srst
= helper_get_output_line("srst", gpiod_chip_srst
, srst_gpio
, 1);
473 gpiod_srst
= helper_get_open_drain_output_line("srst", gpiod_chip_srst
, srst_gpio
, 1);
479 if (is_gpio_valid(led_gpio
)) {
480 gpiod_chip_led
= gpiod_chip_open_by_number(led_gpiochip
);
481 if (!gpiod_chip_led
) {
482 LOG_ERROR("Cannot open LinuxGPIOD led_gpiochip %d", led_gpiochip
);
486 gpiod_led
= helper_get_output_line("led", gpiod_chip_led
, led_gpio
, 0);
496 return ERROR_JTAG_INIT_FAILED
;
499 COMMAND_HELPER(linuxgpiod_helper_gpionum
, const char *name
, int *chip
, int *line
)
503 return ERROR_COMMAND_SYNTAX_ERROR
;
505 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], *chip
);
509 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[i
], *line
);
510 command_print(CMD
, "LinuxGPIOD %s: chip = %d, num = %d", name
, *chip
, *line
);
514 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionums
)
517 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], tck_gpio
);
518 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], tms_gpio
);
519 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[2], tdi_gpio
);
520 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], tdo_gpio
);
521 } else if (CMD_ARGC
!= 0) {
522 return ERROR_COMMAND_SYNTAX_ERROR
;
526 "LinuxGPIOD nums: tck = %d, tms = %d, tdi = %d, tdo = %d",
527 tck_gpio
, tms_gpio
, tdi_gpio
, tdo_gpio
);
532 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tck
)
534 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "tck", &tck_gpiochip
,
538 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tms
)
540 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "tms", &tms_gpiochip
,
544 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdo
)
546 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "tdo", &tdo_gpiochip
,
550 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdi
)
552 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "tdi", &tdi_gpiochip
,
556 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_srst
)
558 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "srst", &srst_gpiochip
,
562 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_trst
)
564 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "trst", &trst_gpiochip
,
568 COMMAND_HANDLER(linuxgpiod_handle_swd_gpionums
)
571 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], swclk_gpio
);
572 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], swdio_gpio
);
573 } else if (CMD_ARGC
!= 0) {
574 return ERROR_COMMAND_SYNTAX_ERROR
;
578 "LinuxGPIOD nums: swclk = %d, swdio = %d",
579 swclk_gpio
, swdio_gpio
);
584 COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swclk
)
586 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "swclk", &swclk_gpiochip
,
590 COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio
)
592 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "swdio", &swdio_gpiochip
,
596 COMMAND_HANDLER(linuxgpiod_handle_gpionum_led
)
598 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum
, "led", &led_gpiochip
,
602 COMMAND_HANDLER(linuxgpiod_handle_gpiochip
)
605 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], gpiochip
);
606 tck_gpiochip
= gpiochip
;
607 tms_gpiochip
= gpiochip
;
608 tdi_gpiochip
= gpiochip
;
609 tdo_gpiochip
= gpiochip
;
610 trst_gpiochip
= gpiochip
;
611 srst_gpiochip
= gpiochip
;
612 swclk_gpiochip
= gpiochip
;
613 swdio_gpiochip
= gpiochip
;
614 led_gpiochip
= gpiochip
;
617 command_print(CMD
, "LinuxGPIOD gpiochip = %d", gpiochip
);
621 static const struct command_registration linuxgpiod_subcommand_handlers
[] = {
624 .handler
= linuxgpiod_handle_jtag_gpionums
,
625 .mode
= COMMAND_CONFIG
,
626 .help
= "gpio numbers for tck, tms, tdi, tdo. (in that order)",
627 .usage
= "tck tms tdi tdo",
631 .handler
= linuxgpiod_handle_jtag_gpionum_tck
,
632 .mode
= COMMAND_CONFIG
,
633 .help
= "gpio chip number (optional) and gpio number for tck.",
634 .usage
= "[chip] tck",
638 .handler
= linuxgpiod_handle_jtag_gpionum_tms
,
639 .mode
= COMMAND_CONFIG
,
640 .help
= "gpio chip number (optional) and gpio number for tms.",
641 .usage
= "[chip] tms",
645 .handler
= linuxgpiod_handle_jtag_gpionum_tdo
,
646 .mode
= COMMAND_CONFIG
,
647 .help
= "gpio chip number (optional) and gpio number for tdo.",
648 .usage
= "[chip] tdo",
652 .handler
= linuxgpiod_handle_jtag_gpionum_tdi
,
653 .mode
= COMMAND_CONFIG
,
654 .help
= "gpio chip number (optional) and gpio number for tdi.",
655 .usage
= "[chip] tdi",
659 .handler
= linuxgpiod_handle_jtag_gpionum_srst
,
660 .mode
= COMMAND_CONFIG
,
661 .help
= "gpio chip number (optional) and gpio number for srst.",
662 .usage
= "[chip] srst",
666 .handler
= linuxgpiod_handle_jtag_gpionum_trst
,
667 .mode
= COMMAND_CONFIG
,
668 .help
= "gpio chip number (optional) and gpio number for trst.",
669 .usage
= "[chip] trst",
673 .handler
= linuxgpiod_handle_swd_gpionums
,
674 .mode
= COMMAND_CONFIG
,
675 .help
= "gpio numbers for swclk, swdio. (in that order)",
676 .usage
= "swclk swdio",
680 .handler
= linuxgpiod_handle_swd_gpionum_swclk
,
681 .mode
= COMMAND_CONFIG
,
682 .help
= "gpio chip number (optional) and gpio number for swclk.",
683 .usage
= "[chip] swclk",
687 .handler
= linuxgpiod_handle_swd_gpionum_swdio
,
688 .mode
= COMMAND_CONFIG
,
689 .help
= "gpio chip number (optional) and gpio number for swdio.",
690 .usage
= "[chip] swdio",
694 .handler
= linuxgpiod_handle_gpionum_led
,
695 .mode
= COMMAND_CONFIG
,
696 .help
= "gpio chip number (optional) and gpio number for LED.",
697 .usage
= "[chip] led",
701 .handler
= linuxgpiod_handle_gpiochip
,
702 .mode
= COMMAND_CONFIG
,
703 .help
= "number of the gpiochip.",
706 COMMAND_REGISTRATION_DONE
709 static const struct command_registration linuxgpiod_command_handlers
[] = {
711 .name
= "linuxgpiod",
713 .help
= "perform linuxgpiod management",
714 .chain
= linuxgpiod_subcommand_handlers
,
717 COMMAND_REGISTRATION_DONE
720 static const char *const linuxgpiod_transport
[] = { "swd", "jtag", NULL
};
722 static struct jtag_interface linuxgpiod_interface
= {
723 .supported
= DEBUG_CAP_TMS_SEQ
,
724 .execute_queue
= bitbang_execute_queue
,
727 struct adapter_driver linuxgpiod_adapter_driver
= {
728 .name
= "linuxgpiod",
729 .transports
= linuxgpiod_transport
,
730 .commands
= linuxgpiod_command_handlers
,
732 .init
= linuxgpiod_init
,
733 .quit
= linuxgpiod_quit
,
734 .reset
= linuxgpiod_reset
,
736 .jtag_ops
= &linuxgpiod_interface
,
737 .swd_ops
= &bitbang_swd
,
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)