linuxgpiod: Allow using multiple GPIO chips.
[openocd.git] / src / jtag / drivers / linuxgpiod.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Bitbang driver for Linux GPIO descriptors through libgpiod
4 * Copyright (C) 2020 Antonio Borneo <borneo.antonio@gmail.com>
5 *
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>
10 */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include <gpiod.h>
17 #include <jtag/interface.h>
18 #include <transport/transport.h>
19 #include "bitbang.h"
20
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;
41
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;
51
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;
61
62 static int last_swclk;
63 static int last_swdio;
64 static bool last_stored;
65 static bool swdio_input;
66
67 /* Bitbang interface read of TDO */
68 static bb_value_t linuxgpiod_read(void)
69 {
70 int retval;
71
72 retval = gpiod_line_get_value(gpiod_tdo);
73 if (retval < 0) {
74 LOG_WARNING("reading tdo failed");
75 return 0;
76 }
77
78 return retval ? BB_HIGH : BB_LOW;
79 }
80
81 /*
82 * Bitbang interface write of TCK, TMS, TDI
83 *
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.
86 */
87 static int linuxgpiod_write(int tck, int tms, int tdi)
88 {
89 static int last_tck;
90 static int last_tms;
91 static int last_tdi;
92
93 static int first_time;
94
95 int retval;
96
97 if (!first_time) {
98 last_tck = !tck;
99 last_tms = !tms;
100 last_tdi = !tdi;
101 first_time = 1;
102 }
103
104 if (tdi != last_tdi) {
105 retval = gpiod_line_set_value(gpiod_tdi, tdi);
106 if (retval < 0)
107 LOG_WARNING("writing tdi failed");
108 }
109
110 if (tms != last_tms) {
111 retval = gpiod_line_set_value(gpiod_tms, tms);
112 if (retval < 0)
113 LOG_WARNING("writing tms failed");
114 }
115
116 /* write clk last */
117 if (tck != last_tck) {
118 retval = gpiod_line_set_value(gpiod_tck, tck);
119 if (retval < 0)
120 LOG_WARNING("writing tck failed");
121 }
122
123 last_tdi = tdi;
124 last_tms = tms;
125 last_tck = tck;
126
127 return ERROR_OK;
128 }
129
130 static int linuxgpiod_swdio_read(void)
131 {
132 int retval;
133
134 retval = gpiod_line_get_value(gpiod_swdio);
135 if (retval < 0) {
136 LOG_WARNING("Fail read swdio");
137 return 0;
138 }
139
140 return retval;
141 }
142
143 static void linuxgpiod_swdio_drive(bool is_output)
144 {
145 int retval;
146
147 /*
148 * FIXME: change direction requires release and re-require the line
149 * https://stackoverflow.com/questions/58735140/
150 * this would change in future libgpiod
151 */
152 gpiod_line_release(gpiod_swdio);
153
154 if (is_output) {
155 retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1);
156 if (retval < 0)
157 LOG_WARNING("Fail request_output line swdio");
158 } else {
159 retval = gpiod_line_request_input(gpiod_swdio, "OpenOCD");
160 if (retval < 0)
161 LOG_WARNING("Fail request_input line swdio");
162 }
163
164 last_stored = false;
165 swdio_input = !is_output;
166 }
167
168 static int linuxgpiod_swd_write(int swclk, int swdio)
169 {
170 int retval;
171
172 if (!swdio_input) {
173 if (!last_stored || (swdio != last_swdio)) {
174 retval = gpiod_line_set_value(gpiod_swdio, swdio);
175 if (retval < 0)
176 LOG_WARNING("Fail set swdio");
177 }
178 }
179
180 /* write swclk last */
181 if (!last_stored || (swclk != last_swclk)) {
182 retval = gpiod_line_set_value(gpiod_swclk, swclk);
183 if (retval < 0)
184 LOG_WARNING("Fail set swclk");
185 }
186
187 last_swdio = swdio;
188 last_swclk = swclk;
189 last_stored = true;
190
191 return ERROR_OK;
192 }
193
194 static int linuxgpiod_blink(int on)
195 {
196 int retval;
197
198 if (!gpiod_led)
199 return ERROR_OK;
200
201 retval = gpiod_line_set_value(gpiod_led, on);
202 if (retval < 0)
203 LOG_WARNING("Fail set led");
204 return retval;
205 }
206
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,
214 };
215
216 /*
217 * Bitbang interface to manipulate reset lines SRST and TRST
218 *
219 * (1) assert or (0) deassert reset lines
220 */
221 static int linuxgpiod_reset(int trst, int srst)
222 {
223 int retval1 = 0, retval2 = 0;
224
225 LOG_DEBUG("linuxgpiod_reset");
226
227 /* assume active low */
228 if (gpiod_srst) {
229 retval1 = gpiod_line_set_value(gpiod_srst, srst ? 0 : 1);
230 if (retval1 < 0)
231 LOG_WARNING("set srst value failed");
232 }
233
234 /* assume active low */
235 if (gpiod_trst) {
236 retval2 = gpiod_line_set_value(gpiod_trst, trst ? 0 : 1);
237 if (retval2 < 0)
238 LOG_WARNING("set trst value failed");
239 }
240
241 return ((retval1 < 0) || (retval2 < 0)) ? ERROR_FAIL : ERROR_OK;
242 }
243
244 /*
245 * Helper function to determine if gpio number is valid
246 *
247 * Assume here that there will be less than 10000 gpios per gpiochip
248 */
249 static bool is_gpio_valid(int gpio)
250 {
251 return gpio >= 0 && gpio < 10000;
252 }
253
254 static bool linuxgpiod_jtag_mode_possible(void)
255 {
256 if (!is_gpio_valid(tck_gpio))
257 return false;
258 if (!is_gpio_valid(tms_gpio))
259 return false;
260 if (!is_gpio_valid(tdi_gpio))
261 return false;
262 if (!is_gpio_valid(tdo_gpio))
263 return false;
264 return true;
265 }
266
267 static bool linuxgpiod_swd_mode_possible(void)
268 {
269 if (!is_gpio_valid(swclk_gpio))
270 return false;
271 if (!is_gpio_valid(swdio_gpio))
272 return false;
273 return true;
274 }
275
276 static inline void helper_release(struct gpiod_line *line)
277 {
278 if (line)
279 gpiod_line_release(line);
280 }
281
282 static int linuxgpiod_quit(void)
283 {
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);
293
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);
312
313 return ERROR_OK;
314 }
315
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)
319 {
320 struct gpiod_line *line;
321 int retval;
322
323 line = gpiod_chip_get_line(gpiod_chip, offset);
324 if (!line) {
325 LOG_ERROR("Error get line %s", label);
326 return NULL;
327 }
328
329 struct gpiod_line_request_config config = {
330 .consumer = "OpenOCD",
331 .request_type = dir,
332 .flags = flags,
333 };
334
335 retval = gpiod_line_request(line, &config, val);
336 if (retval < 0) {
337 LOG_ERROR("Error requesting gpio line %s", label);
338 return NULL;
339 }
340
341 return line;
342 }
343
344 static struct gpiod_line *helper_get_input_line(const char *label,
345 struct gpiod_chip *gpiod_chip, unsigned int offset)
346 {
347 return helper_get_line(label, gpiod_chip, offset, 0,
348 GPIOD_LINE_REQUEST_DIRECTION_INPUT, 0);
349 }
350
351 static struct gpiod_line *helper_get_output_line(const char *label,
352 struct gpiod_chip *gpiod_chip, unsigned int offset, int val)
353 {
354 return helper_get_line(label, gpiod_chip, offset, val,
355 GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0);
356 }
357
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)
360 {
361 return helper_get_line(label, gpiod_chip, offset, val,
362 GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN);
363 }
364
365 static int linuxgpiod_init(void)
366 {
367 LOG_INFO("Linux GPIOD JTAG/SWD bitbang driver");
368
369 bitbang_interface = &linuxgpiod_bitbang;
370
371 /*
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.
375 */
376
377 if (transport_is_jtag()) {
378 if (!linuxgpiod_jtag_mode_possible()) {
379 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
380 goto out_error;
381 }
382
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);
386 goto out_error;
387 }
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);
391 goto out_error;
392 }
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);
396 goto out_error;
397 }
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);
401 goto out_error;
402 }
403
404 gpiod_tdo = helper_get_input_line("tdo", gpiod_chip_tdo, tdo_gpio);
405 if (!gpiod_tdo)
406 goto out_error;
407
408 gpiod_tdi = helper_get_output_line("tdi", gpiod_chip_tdi, tdi_gpio, 0);
409 if (!gpiod_tdi)
410 goto out_error;
411
412 gpiod_tck = helper_get_output_line("tck", gpiod_chip_tck, tck_gpio, 0);
413 if (!gpiod_tck)
414 goto out_error;
415
416 gpiod_tms = helper_get_output_line("tms", gpiod_chip_tms, tms_gpio, 1);
417 if (!gpiod_tms)
418 goto out_error;
419
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);
424 goto out_error;
425 }
426
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);
429 else
430 gpiod_trst = helper_get_output_line("trst", gpiod_chip_trst, trst_gpio, 1);
431
432 if (!gpiod_trst)
433 goto out_error;
434 }
435 }
436
437 if (transport_is_swd()) {
438 if (!linuxgpiod_swd_mode_possible()) {
439 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
440 goto out_error;
441 }
442
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);
446 goto out_error;
447 }
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);
451 goto out_error;
452 }
453
454 gpiod_swclk = helper_get_output_line("swclk", gpiod_chip_swclk, swclk_gpio, 1);
455 if (!gpiod_swclk)
456 goto out_error;
457
458 gpiod_swdio = helper_get_output_line("swdio", gpiod_chip_swdio, swdio_gpio, 1);
459 if (!gpiod_swdio)
460 goto out_error;
461 }
462
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);
467 goto out_error;
468 }
469
470 if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
471 gpiod_srst = helper_get_output_line("srst", gpiod_chip_srst, srst_gpio, 1);
472 else
473 gpiod_srst = helper_get_open_drain_output_line("srst", gpiod_chip_srst, srst_gpio, 1);
474
475 if (!gpiod_srst)
476 goto out_error;
477 }
478
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);
483 goto out_error;
484 }
485
486 gpiod_led = helper_get_output_line("led", gpiod_chip_led, led_gpio, 0);
487 if (!gpiod_led)
488 goto out_error;
489 }
490
491 return ERROR_OK;
492
493 out_error:
494 linuxgpiod_quit();
495
496 return ERROR_JTAG_INIT_FAILED;
497 }
498
499 COMMAND_HELPER(linuxgpiod_helper_gpionum, const char *name, int *chip, int *line)
500 {
501 int i = 0;
502 if (CMD_ARGC > 2)
503 return ERROR_COMMAND_SYNTAX_ERROR;
504 if (CMD_ARGC == 2) {
505 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], *chip);
506 i = 1;
507 }
508 if (CMD_ARGC > 0)
509 COMMAND_PARSE_NUMBER(int, CMD_ARGV[i], *line);
510 command_print(CMD, "LinuxGPIOD %s: chip = %d, num = %d", name, *chip, *line);
511 return ERROR_OK;
512 }
513
514 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionums)
515 {
516 if (CMD_ARGC == 4) {
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;
523 }
524
525 command_print(CMD,
526 "LinuxGPIOD nums: tck = %d, tms = %d, tdi = %d, tdo = %d",
527 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
528
529 return ERROR_OK;
530 }
531
532 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tck)
533 {
534 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tck", &tck_gpiochip,
535 &tck_gpio);
536 }
537
538 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tms)
539 {
540 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tms", &tms_gpiochip,
541 &tms_gpio);
542 }
543
544 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdo)
545 {
546 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tdo", &tdo_gpiochip,
547 &tdo_gpio);
548 }
549
550 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdi)
551 {
552 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tdi", &tdi_gpiochip,
553 &tdi_gpio);
554 }
555
556 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_srst)
557 {
558 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "srst", &srst_gpiochip,
559 &srst_gpio);
560 }
561
562 COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_trst)
563 {
564 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "trst", &trst_gpiochip,
565 &trst_gpio);
566 }
567
568 COMMAND_HANDLER(linuxgpiod_handle_swd_gpionums)
569 {
570 if (CMD_ARGC == 2) {
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;
575 }
576
577 command_print(CMD,
578 "LinuxGPIOD nums: swclk = %d, swdio = %d",
579 swclk_gpio, swdio_gpio);
580
581 return ERROR_OK;
582 }
583
584 COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swclk)
585 {
586 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swclk", &swclk_gpiochip,
587 &swclk_gpio);
588 }
589
590 COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio)
591 {
592 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swdio", &swdio_gpiochip,
593 &swdio_gpio);
594 }
595
596 COMMAND_HANDLER(linuxgpiod_handle_gpionum_led)
597 {
598 return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "led", &led_gpiochip,
599 &led_gpio);
600 }
601
602 COMMAND_HANDLER(linuxgpiod_handle_gpiochip)
603 {
604 if (CMD_ARGC == 1) {
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;
615 }
616
617 command_print(CMD, "LinuxGPIOD gpiochip = %d", gpiochip);
618 return ERROR_OK;
619 }
620
621 static const struct command_registration linuxgpiod_subcommand_handlers[] = {
622 {
623 .name = "jtag_nums",
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",
628 },
629 {
630 .name = "tck_num",
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",
635 },
636 {
637 .name = "tms_num",
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",
642 },
643 {
644 .name = "tdo_num",
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",
649 },
650 {
651 .name = "tdi_num",
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",
656 },
657 {
658 .name = "srst_num",
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",
663 },
664 {
665 .name = "trst_num",
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",
670 },
671 {
672 .name = "swd_nums",
673 .handler = linuxgpiod_handle_swd_gpionums,
674 .mode = COMMAND_CONFIG,
675 .help = "gpio numbers for swclk, swdio. (in that order)",
676 .usage = "swclk swdio",
677 },
678 {
679 .name = "swclk_num",
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",
684 },
685 {
686 .name = "swdio_num",
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",
691 },
692 {
693 .name = "led_num",
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",
698 },
699 {
700 .name = "gpiochip",
701 .handler = linuxgpiod_handle_gpiochip,
702 .mode = COMMAND_CONFIG,
703 .help = "number of the gpiochip.",
704 .usage = "gpiochip",
705 },
706 COMMAND_REGISTRATION_DONE
707 };
708
709 static const struct command_registration linuxgpiod_command_handlers[] = {
710 {
711 .name = "linuxgpiod",
712 .mode = COMMAND_ANY,
713 .help = "perform linuxgpiod management",
714 .chain = linuxgpiod_subcommand_handlers,
715 .usage = "",
716 },
717 COMMAND_REGISTRATION_DONE
718 };
719
720 static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL };
721
722 static struct jtag_interface linuxgpiod_interface = {
723 .supported = DEBUG_CAP_TMS_SEQ,
724 .execute_queue = bitbang_execute_queue,
725 };
726
727 struct adapter_driver linuxgpiod_adapter_driver = {
728 .name = "linuxgpiod",
729 .transports = linuxgpiod_transport,
730 .commands = linuxgpiod_command_handlers,
731
732 .init = linuxgpiod_init,
733 .quit = linuxgpiod_quit,
734 .reset = linuxgpiod_reset,
735
736 .jtag_ops = &linuxgpiod_interface,
737 .swd_ops = &bitbang_swd,
738 };

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)