6db4340e81f9d3c2c6126fc8cf832383405578b2
[openocd.git] / src / jtag / drivers / bcm2835gpio.c
1 /***************************************************************************
2 * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com *
3 * *
4 * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
5 * Based on at91rm9200.c (c) Anders Larsen *
6 * and RPi GPIO examples by Gert van Loo & Dom *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 ***************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <jtag/interface.h>
27 #include <transport/transport.h>
28 #include "bitbang.h"
29
30 #include <sys/mman.h>
31
32 uint32_t bcm2835_peri_base = 0x20000000;
33 #define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
34
35 #define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
36 #define BCM2835_PADS_GPIO_0_27_OFFSET (0x2c / 4)
37
38 /* GPIO setup macros */
39 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
40 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
41 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
42 INP_GPIO(g); \
43 *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0)
44 #define OUT_GPIO(g) SET_MODE_GPIO(g, 1)
45
46 #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */
47 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
48 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
49
50 static int dev_mem_fd;
51 static volatile uint32_t *pio_base;
52
53 static bb_value_t bcm2835gpio_read(void);
54 static int bcm2835gpio_write(int tck, int tms, int tdi);
55
56 static int bcm2835_swdio_read(void);
57 static void bcm2835_swdio_drive(bool is_output);
58 static int bcm2835gpio_swd_write(int swclk, int swdio);
59
60 static int bcm2835gpio_init(void);
61 static int bcm2835gpio_quit(void);
62
63 static struct bitbang_interface bcm2835gpio_bitbang = {
64 .read = bcm2835gpio_read,
65 .write = bcm2835gpio_write,
66 .swdio_read = bcm2835_swdio_read,
67 .swdio_drive = bcm2835_swdio_drive,
68 .swd_write = bcm2835gpio_swd_write,
69 .blink = NULL
70 };
71
72 /* GPIO numbers for each signal. Negative values are invalid */
73 static int tck_gpio = -1;
74 static int tck_gpio_mode;
75 static int tms_gpio = -1;
76 static int tms_gpio_mode;
77 static int tdi_gpio = -1;
78 static int tdi_gpio_mode;
79 static int tdo_gpio = -1;
80 static int tdo_gpio_mode;
81 static int trst_gpio = -1;
82 static int trst_gpio_mode;
83 static int srst_gpio = -1;
84 static int srst_gpio_mode;
85 static int swclk_gpio = -1;
86 static int swclk_gpio_mode;
87 static int swdio_gpio = -1;
88 static int swdio_gpio_mode;
89 static int swdio_dir_gpio = -1;
90 static int swdio_dir_gpio_mode;
91
92 /* Transition delay coefficients */
93 static int speed_coeff = 113714;
94 static int speed_offset = 28;
95 static unsigned int jtag_delay;
96
97 static bb_value_t bcm2835gpio_read(void)
98 {
99 return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW;
100 }
101
102 static int bcm2835gpio_write(int tck, int tms, int tdi)
103 {
104 uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
105 uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
106
107 GPIO_SET = set;
108 GPIO_CLR = clear;
109
110 for (unsigned int i = 0; i < jtag_delay; i++)
111 asm volatile ("");
112
113 return ERROR_OK;
114 }
115
116 static int bcm2835gpio_swd_write(int swclk, int swdio)
117 {
118 uint32_t set = swclk << swclk_gpio | swdio << swdio_gpio;
119 uint32_t clear = !swclk << swclk_gpio | !swdio << swdio_gpio;
120
121 GPIO_SET = set;
122 GPIO_CLR = clear;
123
124 for (unsigned int i = 0; i < jtag_delay; i++)
125 asm volatile ("");
126
127 return ERROR_OK;
128 }
129
130 /* (1) assert or (0) deassert reset lines */
131 static int bcm2835gpio_reset(int trst, int srst)
132 {
133 uint32_t set = 0;
134 uint32_t clear = 0;
135
136 if (trst_gpio > 0) {
137 set |= !trst<<trst_gpio;
138 clear |= trst<<trst_gpio;
139 }
140
141 if (srst_gpio > 0) {
142 set |= !srst<<srst_gpio;
143 clear |= srst<<srst_gpio;
144 }
145
146 GPIO_SET = set;
147 GPIO_CLR = clear;
148
149 return ERROR_OK;
150 }
151
152 static void bcm2835_swdio_drive(bool is_output)
153 {
154 if (swdio_dir_gpio > 0) {
155 if (is_output) {
156 GPIO_SET = 1 << swdio_dir_gpio;
157 OUT_GPIO(swdio_gpio);
158 } else {
159 INP_GPIO(swdio_gpio);
160 GPIO_CLR = 1 << swdio_dir_gpio;
161 }
162 } else {
163 if (is_output)
164 OUT_GPIO(swdio_gpio);
165 else
166 INP_GPIO(swdio_gpio);
167 }
168 }
169
170 static int bcm2835_swdio_read(void)
171 {
172 return !!(GPIO_LEV & 1 << swdio_gpio);
173 }
174
175 static int bcm2835gpio_khz(int khz, int *jtag_speed)
176 {
177 if (!khz) {
178 LOG_DEBUG("RCLK not supported");
179 return ERROR_FAIL;
180 }
181 *jtag_speed = speed_coeff/khz - speed_offset;
182 if (*jtag_speed < 0)
183 *jtag_speed = 0;
184 return ERROR_OK;
185 }
186
187 static int bcm2835gpio_speed_div(int speed, int *khz)
188 {
189 *khz = speed_coeff/(speed + speed_offset);
190 return ERROR_OK;
191 }
192
193 static int bcm2835gpio_speed(int speed)
194 {
195 jtag_delay = speed;
196 return ERROR_OK;
197 }
198
199 static int is_gpio_valid(int gpio)
200 {
201 return gpio >= 0 && gpio <= 53;
202 }
203
204 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
205 {
206 if (CMD_ARGC == 4) {
207 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
208 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
209 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
210 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
211 } else if (CMD_ARGC != 0) {
212 return ERROR_COMMAND_SYNTAX_ERROR;
213 }
214
215 command_print(CMD,
216 "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
217 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
218
219 return ERROR_OK;
220 }
221
222 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck)
223 {
224 if (CMD_ARGC == 1)
225 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
226
227 command_print(CMD, "BCM2835 GPIO config: tck = %d", tck_gpio);
228 return ERROR_OK;
229 }
230
231 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms)
232 {
233 if (CMD_ARGC == 1)
234 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
235
236 command_print(CMD, "BCM2835 GPIO config: tms = %d", tms_gpio);
237 return ERROR_OK;
238 }
239
240 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo)
241 {
242 if (CMD_ARGC == 1)
243 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
244
245 command_print(CMD, "BCM2835 GPIO config: tdo = %d", tdo_gpio);
246 return ERROR_OK;
247 }
248
249 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi)
250 {
251 if (CMD_ARGC == 1)
252 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
253
254 command_print(CMD, "BCM2835 GPIO config: tdi = %d", tdi_gpio);
255 return ERROR_OK;
256 }
257
258 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst)
259 {
260 if (CMD_ARGC == 1)
261 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
262
263 command_print(CMD, "BCM2835 GPIO config: srst = %d", srst_gpio);
264 return ERROR_OK;
265 }
266
267 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst)
268 {
269 if (CMD_ARGC == 1)
270 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
271
272 command_print(CMD, "BCM2835 GPIO config: trst = %d", trst_gpio);
273 return ERROR_OK;
274 }
275
276 COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionums)
277 {
278 if (CMD_ARGC == 2) {
279 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
280 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
281 } else if (CMD_ARGC != 0) {
282 return ERROR_COMMAND_SYNTAX_ERROR;
283 }
284
285 command_print(CMD,
286 "BCM2835 GPIO nums: swclk = %d, swdio = %d",
287 swclk_gpio, swdio_gpio);
288
289 return ERROR_OK;
290 }
291
292 COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swclk)
293 {
294 if (CMD_ARGC == 1)
295 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
296
297 command_print(CMD, "BCM2835 num: swclk = %d", swclk_gpio);
298 return ERROR_OK;
299 }
300
301 COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swdio)
302 {
303 if (CMD_ARGC == 1)
304 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
305
306 command_print(CMD, "BCM2835 num: swdio = %d", swdio_gpio);
307 return ERROR_OK;
308 }
309
310 COMMAND_HANDLER(bcm2835gpio_handle_swd_dir_gpionum_swdio)
311 {
312 if (CMD_ARGC == 1)
313 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_dir_gpio);
314
315 command_print(CMD, "BCM2835 num: swdio_dir = %d", swdio_dir_gpio);
316 return ERROR_OK;
317 }
318
319 COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
320 {
321 if (CMD_ARGC == 2) {
322 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
323 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
324 }
325
326 command_print(CMD, "BCM2835 GPIO: speed_coeffs = %d, speed_offset = %d",
327 speed_coeff, speed_offset);
328 return ERROR_OK;
329 }
330
331 COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
332 {
333 if (CMD_ARGC == 1)
334 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
335
336 command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
337 bcm2835_peri_base);
338 return ERROR_OK;
339 }
340
341 static const struct command_registration bcm2835gpio_command_handlers[] = {
342 {
343 .name = "bcm2835gpio_jtag_nums",
344 .handler = &bcm2835gpio_handle_jtag_gpionums,
345 .mode = COMMAND_CONFIG,
346 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
347 .usage = "[tck tms tdi tdo]",
348 },
349 {
350 .name = "bcm2835gpio_tck_num",
351 .handler = &bcm2835gpio_handle_jtag_gpionum_tck,
352 .mode = COMMAND_CONFIG,
353 .help = "gpio number for tck.",
354 .usage = "[tck]",
355 },
356 {
357 .name = "bcm2835gpio_tms_num",
358 .handler = &bcm2835gpio_handle_jtag_gpionum_tms,
359 .mode = COMMAND_CONFIG,
360 .help = "gpio number for tms.",
361 .usage = "[tms]",
362 },
363 {
364 .name = "bcm2835gpio_tdo_num",
365 .handler = &bcm2835gpio_handle_jtag_gpionum_tdo,
366 .mode = COMMAND_CONFIG,
367 .help = "gpio number for tdo.",
368 .usage = "[tdo]",
369 },
370 {
371 .name = "bcm2835gpio_tdi_num",
372 .handler = &bcm2835gpio_handle_jtag_gpionum_tdi,
373 .mode = COMMAND_CONFIG,
374 .help = "gpio number for tdi.",
375 .usage = "[tdi]",
376 },
377 {
378 .name = "bcm2835gpio_swd_nums",
379 .handler = &bcm2835gpio_handle_swd_gpionums,
380 .mode = COMMAND_CONFIG,
381 .help = "gpio numbers for swclk, swdio. (in that order)",
382 .usage = "[swclk swdio]",
383 },
384 {
385 .name = "bcm2835gpio_swclk_num",
386 .handler = &bcm2835gpio_handle_swd_gpionum_swclk,
387 .mode = COMMAND_CONFIG,
388 .help = "gpio number for swclk.",
389 .usage = "[swclk]",
390 },
391 {
392 .name = "bcm2835gpio_swdio_num",
393 .handler = &bcm2835gpio_handle_swd_gpionum_swdio,
394 .mode = COMMAND_CONFIG,
395 .help = "gpio number for swdio.",
396 .usage = "[swdio]",
397 },
398 {
399 .name = "bcm2835gpio_swdio_dir_num",
400 .handler = &bcm2835gpio_handle_swd_dir_gpionum_swdio,
401 .mode = COMMAND_CONFIG,
402 .help = "gpio number for swdio direction control pin (set=output mode, clear=input mode)",
403 .usage = "[swdio_dir]",
404 },
405 {
406 .name = "bcm2835gpio_srst_num",
407 .handler = &bcm2835gpio_handle_jtag_gpionum_srst,
408 .mode = COMMAND_CONFIG,
409 .help = "gpio number for srst.",
410 .usage = "[srst]",
411 },
412 {
413 .name = "bcm2835gpio_trst_num",
414 .handler = &bcm2835gpio_handle_jtag_gpionum_trst,
415 .mode = COMMAND_CONFIG,
416 .help = "gpio number for trst.",
417 .usage = "[trst]",
418 },
419 {
420 .name = "bcm2835gpio_speed_coeffs",
421 .handler = &bcm2835gpio_handle_speed_coeffs,
422 .mode = COMMAND_CONFIG,
423 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
424 .usage = "[SPEED_COEFF SPEED_OFFSET]",
425 },
426 {
427 .name = "bcm2835gpio_peripheral_base",
428 .handler = &bcm2835gpio_handle_peripheral_base,
429 .mode = COMMAND_CONFIG,
430 .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
431 .usage = "[base]",
432 },
433
434 COMMAND_REGISTRATION_DONE
435 };
436
437 static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
438
439 static struct jtag_interface bcm2835gpio_interface = {
440 .supported = DEBUG_CAP_TMS_SEQ,
441 .execute_queue = bitbang_execute_queue,
442 };
443
444 struct adapter_driver bcm2835gpio_adapter_driver = {
445 .name = "bcm2835gpio",
446 .transports = bcm2835_transports,
447 .commands = bcm2835gpio_command_handlers,
448
449 .init = bcm2835gpio_init,
450 .quit = bcm2835gpio_quit,
451 .reset = bcm2835gpio_reset,
452 .speed = bcm2835gpio_speed,
453 .khz = bcm2835gpio_khz,
454 .speed_div = bcm2835gpio_speed_div,
455
456 .jtag_ops = &bcm2835gpio_interface,
457 .swd_ops = &bitbang_swd,
458 };
459
460 static bool bcm2835gpio_jtag_mode_possible(void)
461 {
462 if (!is_gpio_valid(tck_gpio))
463 return 0;
464 if (!is_gpio_valid(tms_gpio))
465 return 0;
466 if (!is_gpio_valid(tdi_gpio))
467 return 0;
468 if (!is_gpio_valid(tdo_gpio))
469 return 0;
470 return 1;
471 }
472
473 static bool bcm2835gpio_swd_mode_possible(void)
474 {
475 if (!is_gpio_valid(swclk_gpio))
476 return 0;
477 if (!is_gpio_valid(swdio_gpio))
478 return 0;
479 return 1;
480 }
481
482 static int bcm2835gpio_init(void)
483 {
484 bitbang_interface = &bcm2835gpio_bitbang;
485
486 LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver");
487
488 if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) {
489 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
490 return ERROR_JTAG_INIT_FAILED;
491 }
492
493 if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) {
494 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
495 return ERROR_JTAG_INIT_FAILED;
496 }
497
498 dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
499 if (dev_mem_fd < 0) {
500 LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
501 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
502 }
503 if (dev_mem_fd < 0) {
504 LOG_ERROR("open: %s", strerror(errno));
505 return ERROR_JTAG_INIT_FAILED;
506 }
507
508 pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
509 MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE);
510
511 if (pio_base == MAP_FAILED) {
512 LOG_ERROR("mmap: %s", strerror(errno));
513 close(dev_mem_fd);
514 return ERROR_JTAG_INIT_FAILED;
515 }
516
517 static volatile uint32_t *pads_base;
518 pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
519 MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
520
521 if (pads_base == MAP_FAILED) {
522 LOG_ERROR("mmap: %s", strerror(errno));
523 close(dev_mem_fd);
524 return ERROR_JTAG_INIT_FAILED;
525 }
526
527 /* set 4mA drive strength, slew rate limited, hysteresis on */
528 pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
529
530 /*
531 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
532 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
533 */
534 if (transport_is_jtag()) {
535 tdo_gpio_mode = MODE_GPIO(tdo_gpio);
536 tdi_gpio_mode = MODE_GPIO(tdi_gpio);
537 tck_gpio_mode = MODE_GPIO(tck_gpio);
538 tms_gpio_mode = MODE_GPIO(tms_gpio);
539
540 INP_GPIO(tdo_gpio);
541
542 GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio;
543 GPIO_SET = 1<<tms_gpio;
544
545 OUT_GPIO(tdi_gpio);
546 OUT_GPIO(tck_gpio);
547 OUT_GPIO(tms_gpio);
548
549 if (trst_gpio != -1) {
550 trst_gpio_mode = MODE_GPIO(trst_gpio);
551 GPIO_SET = 1 << trst_gpio;
552 OUT_GPIO(trst_gpio);
553 }
554 }
555
556 if (transport_is_swd()) {
557 swclk_gpio_mode = MODE_GPIO(swclk_gpio);
558 swdio_gpio_mode = MODE_GPIO(swdio_gpio);
559
560 GPIO_CLR = 1<<swdio_gpio | 1<<swclk_gpio;
561
562 OUT_GPIO(swclk_gpio);
563 OUT_GPIO(swdio_gpio);
564 }
565
566 if (srst_gpio != -1) {
567 srst_gpio_mode = MODE_GPIO(srst_gpio);
568 GPIO_SET = 1 << srst_gpio;
569 OUT_GPIO(srst_gpio);
570 }
571
572 if (swdio_dir_gpio != -1) {
573 swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio);
574 GPIO_SET = 1 << swdio_dir_gpio;
575 OUT_GPIO(swdio_dir_gpio);
576 }
577
578 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
579 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
580 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
581
582 return ERROR_OK;
583 }
584
585 static int bcm2835gpio_quit(void)
586 {
587 if (transport_is_jtag()) {
588 SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode);
589 SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode);
590 SET_MODE_GPIO(tck_gpio, tck_gpio_mode);
591 SET_MODE_GPIO(tms_gpio, tms_gpio_mode);
592 if (trst_gpio != -1)
593 SET_MODE_GPIO(trst_gpio, trst_gpio_mode);
594 }
595
596 if (transport_is_swd()) {
597 SET_MODE_GPIO(swclk_gpio, swclk_gpio_mode);
598 SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode);
599 }
600
601 if (srst_gpio != -1)
602 SET_MODE_GPIO(srst_gpio, srst_gpio_mode);
603
604 if (swdio_dir_gpio != -1)
605 SET_MODE_GPIO(swdio_dir_gpio, swdio_dir_gpio_mode);
606
607 return ERROR_OK;
608 }

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)