1 /***************************************************************************
2 * Copyright (C) 2007 by Pavel Chromy *
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. *
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. *
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 ***************************************************************************/
23 * Holds driver for PRESTO programmer from ASIX.
24 * http://tools.asix.net/prg_presto.htm
34 #include <jtag/interface.h>
35 #include <helper/time_support.h>
39 /* PRESTO access library includes */
40 #if BUILD_PRESTO_FTD2XX == 1
42 #elif BUILD_PRESTO_LIBFTDI == 1
45 #error "BUG: either FTD2XX and LIBFTDI has to be used"
48 /* -------------------------------------------------------------------------- */
50 #define FT_DEVICE_NAME_LEN 64
51 #define FT_DEVICE_SERNUM_LEN 64
53 #define PRESTO_VID_PID 0x0403f1a0
54 #define PRESTO_VID (0x0403)
55 #define PRESTO_PID (0xf1a0)
57 #define BUFFER_SIZE (64*62)
60 #if BUILD_PRESTO_FTD2XX == 1
63 #elif BUILD_PRESTO_LIBFTDI == 1
64 struct ftdi_context ftdic
;
68 char serial
[FT_DEVICE_SERNUM_LEN
];
70 uint8_t buff_out
[BUFFER_SIZE
];
73 uint8_t buff_in
[BUFFER_SIZE
];
74 int buff_in_exp
; /* expected in buffer length */
75 int buff_in_len
; /* length of data received */
78 unsigned long total_out
;
79 unsigned long total_in
;
81 int jtag_tms
; /* last tms state */
82 int jtag_tck
; /* last tck state */
83 int jtag_rst
; /* last trst state */
91 static struct presto presto_state
;
92 static struct presto
*presto
= &presto_state
;
94 static uint8_t presto_init_seq
[] =
96 0x80, 0xA0, 0xA8, 0xB0, 0xC0, 0xE0
99 static int presto_write(uint8_t *buf
, uint32_t size
)
101 #if BUILD_PRESTO_FTD2XX == 1
103 if ((presto
->status
= FT_Write(presto
->handle
, buf
, size
, &ftbytes
)) != FT_OK
)
105 LOG_ERROR("FT_Write returned: %lu", presto
->status
);
106 return ERROR_JTAG_DEVICE_ERROR
;
109 #elif BUILD_PRESTO_LIBFTDI == 1
111 if ((presto
->retval
= ftdi_write_data(&presto
->ftdic
, buf
, size
)) < 0)
113 LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&presto
->ftdic
));
114 return ERROR_JTAG_DEVICE_ERROR
;
116 ftbytes
= presto
->retval
;
121 LOG_ERROR("couldn't write the requested number of bytes to PRESTO (%u < %u)",
122 (unsigned)ftbytes
, (unsigned)size
);
123 return ERROR_JTAG_DEVICE_ERROR
;
129 static int presto_read(uint8_t* buf
, uint32_t size
)
131 #if BUILD_PRESTO_FTD2XX == 1
133 if ((presto
->status
= FT_Read(presto
->handle
, buf
, size
, &ftbytes
)) != FT_OK
)
135 LOG_ERROR("FT_Read returned: %lu", presto
->status
);
136 return ERROR_JTAG_DEVICE_ERROR
;
139 #elif BUILD_PRESTO_LIBFTDI == 1
140 uint32_t ftbytes
= 0;
142 struct timeval timeout
, now
;
143 gettimeofday(&timeout
, NULL
);
144 timeval_add_time(&timeout
, 1, 0); /* one second timeout */
146 while (ftbytes
< size
)
148 if ((presto
->retval
= ftdi_read_data(&presto
->ftdic
, buf
+ ftbytes
, size
- ftbytes
)) < 0)
150 LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&presto
->ftdic
));
151 return ERROR_JTAG_DEVICE_ERROR
;
153 ftbytes
+= presto
->retval
;
155 gettimeofday(&now
, NULL
);
156 if ((now
.tv_sec
> timeout
.tv_sec
) || ((now
.tv_sec
== timeout
.tv_sec
) && (now
.tv_usec
> timeout
.tv_usec
)))
163 /* this is just a warning, there might have been timeout when detecting PRESTO, which is not fatal */
164 LOG_WARNING("couldn't read the requested number of bytes from PRESTO (%u < %u)",
165 (unsigned)ftbytes
, (unsigned)size
);
166 return ERROR_JTAG_DEVICE_ERROR
;
172 #if BUILD_PRESTO_FTD2XX == 1
173 static int presto_open_ftd2xx(char *req_serial
)
178 char devname
[FT_DEVICE_NAME_LEN
];
184 presto
->handle
= (FT_HANDLE
)INVALID_HANDLE_VALUE
;
187 /* Add non-standard Vid/Pid to the linux driver */
188 if ((presto
->status
= FT_SetVIDPID(PRESTO_VID
, PRESTO_PID
)) != FT_OK
)
190 LOG_ERROR("couldn't add PRESTO VID/PID");
195 if ((presto
->status
= FT_ListDevices(&numdevs
, NULL
, FT_LIST_NUMBER_ONLY
)) != FT_OK
)
197 LOG_ERROR("FT_ListDevices failed: %i", (int)presto
->status
);
198 return ERROR_JTAG_DEVICE_ERROR
;
201 LOG_DEBUG("FTDI devices available: %lu", numdevs
);
202 for (i
= 0; i
< numdevs
; i
++)
204 if ((presto
->status
= FT_Open(i
, &(presto
->handle
))) != FT_OK
)
206 /* this is not fatal, the device may be legitimately open by other process, hence debug message only */
207 LOG_DEBUG("FT_Open failed: %i", (int)presto
->status
);
210 LOG_DEBUG("FTDI device %i open", (int)i
);
212 if ((presto
->status
= FT_GetDeviceInfo(presto
->handle
, &device
, &vidpid
,
213 presto
->serial
, devname
, NULL
)) == FT_OK
)
215 if (vidpid
== PRESTO_VID_PID
216 && (req_serial
== NULL
|| !strcmp(presto
->serial
, req_serial
)))
220 LOG_DEBUG("FT_GetDeviceInfo failed: %lu", presto
->status
);
222 LOG_DEBUG("FTDI device %i does not match, closing", (int)i
);
223 FT_Close(presto
->handle
);
224 presto
->handle
= (FT_HANDLE
)INVALID_HANDLE_VALUE
;
227 if (presto
->handle
== (FT_HANDLE
)INVALID_HANDLE_VALUE
)
228 return ERROR_JTAG_DEVICE_ERROR
; /* presto not open, return */
230 if ((presto
->status
= FT_SetLatencyTimer(presto
->handle
, 1)) != FT_OK
)
231 return ERROR_JTAG_DEVICE_ERROR
;
234 if ((presto
->status
= FT_SetTimeouts(presto
->handle
, 100, 0)) != FT_OK
)
235 return ERROR_JTAG_DEVICE_ERROR
;
237 if ((presto
->status
= FT_Purge(presto
->handle
, FT_PURGE_TX
| FT_PURGE_RX
)) != FT_OK
)
238 return ERROR_JTAG_DEVICE_ERROR
;
241 if ((presto
->status
= FT_Write(presto
->handle
, &presto_data
, 1, &ftbytes
)) != FT_OK
)
242 return ERROR_JTAG_DEVICE_ERROR
;
244 /* delay between first write/read turnaround (after purge?) necessary under Linux for unknown reason,
245 probably a bug in library threading */
247 if ((presto
->status
= FT_Read(presto
->handle
, &presto_data
, 1, &ftbytes
)) != FT_OK
)
248 return ERROR_JTAG_DEVICE_ERROR
;
252 LOG_DEBUG("PRESTO reset");
254 if ((presto
->status
= FT_Purge(presto
->handle
, FT_PURGE_TX
| FT_PURGE_RX
)) != FT_OK
)
255 return ERROR_JTAG_DEVICE_ERROR
;
256 if ((presto
->status
= FT_SetBitMode(presto
->handle
, 0x80, 1)) != FT_OK
)
257 return ERROR_JTAG_DEVICE_ERROR
;
258 if ((presto
->status
= FT_SetBaudRate(presto
->handle
, 9600)) != FT_OK
)
259 return ERROR_JTAG_DEVICE_ERROR
;
262 for (i
= 0; i
< 4 * 62; i
++)
263 if ((presto
->status
= FT_Write(presto
->handle
, &presto_data
, 1, &ftbytes
)) != FT_OK
)
264 return ERROR_JTAG_DEVICE_ERROR
;
268 if ((presto
->status
= FT_SetBitMode(presto
->handle
, 0x00, 0)) != FT_OK
)
269 return ERROR_JTAG_DEVICE_ERROR
;
271 if ((presto
->status
= FT_Purge(presto
->handle
, FT_PURGE_TX
| FT_PURGE_RX
)) != FT_OK
)
272 return ERROR_JTAG_DEVICE_ERROR
;
275 if ((presto
->status
= FT_Write(presto
->handle
, &presto_data
, 1, &ftbytes
)) != FT_OK
)
276 return ERROR_JTAG_DEVICE_ERROR
;
278 /* delay between first write/read turnaround (after purge?) necessary under Linux for unknown reason,
279 probably a bug in library threading */
281 if ((presto
->status
= FT_Read(presto
->handle
, &presto_data
, 1, &ftbytes
)) != FT_OK
)
282 return ERROR_JTAG_DEVICE_ERROR
;
286 LOG_DEBUG("PRESTO not responding");
287 return ERROR_JTAG_DEVICE_ERROR
;
291 if ((presto
->status
= FT_SetTimeouts(presto
->handle
, 0, 0)) != FT_OK
)
292 return ERROR_JTAG_DEVICE_ERROR
;
295 presto
->status
= FT_Write(presto
->handle
, &presto_init_seq
, sizeof(presto_init_seq
), &ftbytes
);
296 if (presto
->status
!= FT_OK
|| ftbytes
!= sizeof(presto_init_seq
))
297 return ERROR_JTAG_DEVICE_ERROR
;
302 #elif BUILD_PRESTO_LIBFTDI == 1
303 static int presto_open_libftdi(char *req_serial
)
307 LOG_DEBUG("searching for PRESTO using libftdi");
309 /* initialize FTDI context structure */
310 if (ftdi_init(&presto
->ftdic
) < 0)
312 LOG_ERROR("unable to init libftdi: %s", presto
->ftdic
.error_str
);
313 return ERROR_JTAG_DEVICE_ERROR
;
316 /* context, vendor id, product id */
317 if (ftdi_usb_open_desc(&presto
->ftdic
, PRESTO_VID
, PRESTO_PID
, NULL
, req_serial
) < 0)
319 LOG_ERROR("unable to open PRESTO: %s", presto
->ftdic
.error_str
);
320 return ERROR_JTAG_DEVICE_ERROR
;
323 if (ftdi_usb_reset(&presto
->ftdic
) < 0)
325 LOG_ERROR("unable to reset PRESTO device");
326 return ERROR_JTAG_DEVICE_ERROR
;
329 if (ftdi_set_latency_timer(&presto
->ftdic
, 1) < 0)
331 LOG_ERROR("unable to set latency timer");
332 return ERROR_JTAG_DEVICE_ERROR
;
335 if (ftdi_usb_purge_buffers(&presto
->ftdic
) < 0)
337 LOG_ERROR("unable to purge PRESTO buffers");
338 return ERROR_JTAG_DEVICE_ERROR
;
342 if (presto_write(&presto_data
, 1) != ERROR_OK
)
344 LOG_ERROR("error writing to PRESTO");
345 return ERROR_JTAG_DEVICE_ERROR
;
348 if (presto_read(&presto_data
, 1) != ERROR_OK
)
350 LOG_DEBUG("no response from PRESTO, retrying");
352 if (ftdi_usb_purge_buffers(&presto
->ftdic
) < 0)
353 return ERROR_JTAG_DEVICE_ERROR
;
356 if (presto_write(&presto_data
, 1) != ERROR_OK
)
357 return ERROR_JTAG_DEVICE_ERROR
;
359 if (presto_read(&presto_data
, 1) != ERROR_OK
)
361 LOG_ERROR("no response from PRESTO, giving up");
362 return ERROR_JTAG_DEVICE_ERROR
;
366 if (presto_write(presto_init_seq
, sizeof(presto_init_seq
)) != ERROR_OK
)
368 LOG_ERROR("error writing PRESTO init sequence");
369 return ERROR_JTAG_DEVICE_ERROR
;
374 #endif /* BUILD_PRESTO_LIBFTDI == 1 */
376 static int presto_open(char *req_serial
)
378 presto
->buff_out_pos
= 0;
379 presto
->buff_in_pos
= 0;
380 presto
->buff_in_len
= 0;
381 presto
->buff_in_exp
= 0;
383 presto
->total_out
= 0;
384 presto
->total_in
= 0;
386 presto
->jtag_tms
= 0;
387 presto
->jtag_tck
= 0;
388 presto
->jtag_rst
= 0;
389 presto
->jtag_tdi_data
= 0;
390 presto
->jtag_tdi_count
= 0;
392 presto
->jtag_speed
= 0;
394 #if BUILD_PRESTO_FTD2XX == 1
395 return presto_open_ftd2xx(req_serial
);
396 #elif BUILD_PRESTO_LIBFTDI == 1
397 return presto_open_libftdi(req_serial
);
401 static int presto_close(void)
404 int result
= ERROR_OK
;
406 #if BUILD_PRESTO_FTD2XX == 1
407 unsigned long ftbytes
;
409 if (presto
->handle
== (FT_HANDLE
)INVALID_HANDLE_VALUE
)
412 presto
->status
= FT_Purge(presto
->handle
, FT_PURGE_TX
| FT_PURGE_RX
);
413 if (presto
->status
!= FT_OK
)
414 result
= ERROR_JTAG_DEVICE_ERROR
;
416 presto
->status
= FT_Write(presto
->handle
, &presto_init_seq
, sizeof(presto_init_seq
), &ftbytes
);
417 if (presto
->status
!= FT_OK
|| ftbytes
!= sizeof(presto_init_seq
))
418 result
= ERROR_JTAG_DEVICE_ERROR
;
420 if ((presto
->status
= FT_SetLatencyTimer(presto
->handle
, 16)) != FT_OK
)
421 result
= ERROR_JTAG_DEVICE_ERROR
;
423 if ((presto
->status
= FT_Close(presto
->handle
)) != FT_OK
)
424 result
= ERROR_JTAG_DEVICE_ERROR
;
426 presto
->handle
= (FT_HANDLE
)INVALID_HANDLE_VALUE
;
428 #elif BUILD_PRESTO_LIBFTDI == 1
430 if ((presto
->retval
= ftdi_write_data(&presto
->ftdic
, presto_init_seq
, sizeof(presto_init_seq
))) != sizeof(presto_init_seq
))
431 result
= ERROR_JTAG_DEVICE_ERROR
;
433 if ((presto
->retval
= ftdi_set_latency_timer(&presto
->ftdic
, 16)) < 0)
434 result
= ERROR_JTAG_DEVICE_ERROR
;
436 if ((presto
->retval
= ftdi_usb_close(&presto
->ftdic
)) < 0)
437 result
= ERROR_JTAG_DEVICE_ERROR
;
439 ftdi_deinit(&presto
->ftdic
);
445 static int presto_flush(void)
447 if (presto
->buff_out_pos
== 0)
450 #if BUILD_PRESTO_FTD2XX == 1
451 if (presto
->status
!= FT_OK
)
452 #elif BUILD_PRESTO_LIBFTDI == 1
453 if (presto
->retval
< 0)
456 LOG_DEBUG("error in previous communication, canceling I/O operation");
457 return ERROR_JTAG_DEVICE_ERROR
;
460 if (presto_write(presto
->buff_out
, presto
->buff_out_pos
) != ERROR_OK
)
462 presto
->buff_out_pos
= 0;
463 return ERROR_JTAG_DEVICE_ERROR
;
466 presto
->total_out
+= presto
->buff_out_pos
;
467 presto
->buff_out_pos
= 0;
469 if (presto
->buff_in_exp
== 0)
472 presto
->buff_in_pos
= 0;
473 presto
->buff_in_len
= 0;
475 if (presto_read(presto
->buff_in
, presto
->buff_in_exp
) != ERROR_OK
)
477 presto
->buff_in_exp
= 0;
478 return ERROR_JTAG_DEVICE_ERROR
;
481 presto
->total_in
+= presto
->buff_in_exp
;
482 presto
->buff_in_len
= presto
->buff_in_exp
;
483 presto
->buff_in_exp
= 0;
488 static int presto_sendbyte(int data
)
490 if (data
== EOF
) return presto_flush();
492 if (presto
->buff_out_pos
< BUFFER_SIZE
)
494 presto
->buff_out
[presto
->buff_out_pos
++] = (uint8_t)data
;
495 if (((data
& 0xC0) == 0x40) || ((data
& 0xD0)== 0xD0))
496 presto
->buff_in_exp
++;
499 return ERROR_JTAG_DEVICE_ERROR
;
501 #if BUILD_PRESTO_FTD2XX == 1
502 if (presto
->buff_out_pos
>= BUFFER_SIZE
)
503 #elif BUILD_PRESTO_LIBFTDI == 1
504 /* libftdi does not do background read, be sure that USB IN buffer does not overflow (128 bytes only!) */
505 if (presto
->buff_out_pos
>= BUFFER_SIZE
|| presto
->buff_in_exp
== 128)
507 return presto_flush();
513 static int presto_getbyte(void)
515 if (presto
->buff_in_pos
< presto
->buff_in_len
)
516 return presto
->buff_in
[presto
->buff_in_pos
++];
518 if (presto
->buff_in_exp
== 0)
521 if (presto_flush() != ERROR_OK
)
524 if (presto
->buff_in_pos
< presto
->buff_in_len
)
525 return presto
->buff_in
[presto
->buff_in_pos
++];
531 /* -------------------------------------------------------------------------- */
533 static int presto_tdi_flush(void)
535 if (presto
->jtag_tdi_count
== 0)
538 if (presto
->jtag_tck
== 0)
540 LOG_ERROR("BUG: unexpected TAP condition, TCK low");
544 presto
->jtag_tdi_data
|= (presto
->jtag_tdi_count
- 1) << 4;
545 presto_sendbyte(presto
->jtag_tdi_data
);
546 presto
->jtag_tdi_count
= 0;
547 presto
->jtag_tdi_data
= 0;
552 static int presto_tck_idle(void)
554 if (presto
->jtag_tck
== 1)
556 presto_sendbyte(0xCA);
557 presto
->jtag_tck
= 0;
563 /* -------------------------------------------------------------------------- */
565 static int presto_bitq_out(int tms
, int tdi
, int tdo_req
)
570 if (presto
->jtag_tck
== 0)
572 presto_sendbyte(0xA4); /* LED idicator - JTAG active */
574 else if (presto
->jtag_speed
== 0 && !tdo_req
&& tms
== presto
->jtag_tms
)
576 presto
->jtag_tdi_data
|= (tdi
!= 0) << presto
->jtag_tdi_count
;
578 if (++presto
->jtag_tdi_count
== 4)
586 cmd
= tdi
? 0xCB : 0xCA;
587 presto_sendbyte(cmd
);
589 if (tms
!= presto
->jtag_tms
)
591 presto_sendbyte((tms
? 0xEC : 0xE8) | (presto
->jtag_rst
? 0x02 : 0));
592 presto
->jtag_tms
= tms
;
595 /* delay with TCK low */
596 for (i
= presto
->jtag_speed
; i
> 1; i
--)
597 presto_sendbyte(cmd
);
600 presto_sendbyte(cmd
| (tdo_req
? 0x10 : 0));
602 /* delay with TCK high */
603 for (i
= presto
->jtag_speed
; i
> 1; i
--)
604 presto_sendbyte(cmd
);
606 presto
->jtag_tck
= 1;
611 static int presto_bitq_flush(void)
616 presto_sendbyte(0xA0); /* LED idicator - JTAG idle */
618 return presto_flush();
621 static int presto_bitq_in_rdy(void)
623 if (presto
->buff_in_pos
>= presto
->buff_in_len
)
625 return presto
->buff_in_len
-presto
->buff_in_pos
;
628 static int presto_bitq_in(void)
630 if (presto
->buff_in_pos
>= presto
->buff_in_len
)
632 if (presto
->buff_in
[presto
->buff_in_pos
++]&0x08) return 1;
636 static int presto_bitq_sleep(unsigned long us
)
650 waits
= us
/ 170 + 2;
652 presto_sendbyte(0x80);
657 static int presto_bitq_reset(int trst
, int srst
)
662 /* add a delay after possible TCK transition */
663 presto_sendbyte(0x80);
664 presto_sendbyte(0x80);
666 presto
->jtag_rst
= trst
|| srst
;
667 presto_sendbyte((presto
->jtag_rst
? 0xEA : 0xE8) | (presto
->jtag_tms
? 0x04 : 0));
672 static struct bitq_interface presto_bitq
= {
673 .out
= &presto_bitq_out
,
674 .flush
= &presto_bitq_flush
,
675 .sleep
= &presto_bitq_sleep
,
676 .reset
= &presto_bitq_reset
,
677 .in_rdy
= &presto_bitq_in_rdy
,
678 .in
= &presto_bitq_in
,
681 /* -------------------------------------------------------------------------- */
683 static int presto_adapter_khz(int khz
, int *jtag_speed
)
688 return ERROR_INVALID_ARGUMENTS
;
691 if (khz
>= 3000) *jtag_speed
= 0;
692 else *jtag_speed
= (1000 + khz
-1)/khz
;
697 static int presto_jtag_speed_div(int speed
, int *khz
)
699 if ((speed
< 0) || (speed
> 1000))
702 return ERROR_INVALID_ARGUMENTS
;
705 if (speed
== 0) *khz
= 3000;
706 else *khz
= 1000/speed
;
711 static int presto_jtag_speed(int speed
)
715 if (presto_jtag_speed_div(speed
, &khz
))
717 return ERROR_INVALID_ARGUMENTS
;
720 presto
->jtag_speed
= speed
;
723 LOG_INFO("setting speed to %d, max. TCK freq. is %d MHz", speed
, khz
/1000);
725 LOG_INFO("setting speed to %d, max. TCK freq. is %d kHz", speed
, khz
);
730 static char *presto_serial
;
732 COMMAND_HANDLER(presto_handle_serial_command
)
738 presto_serial
= strdup(CMD_ARGV
[0]);
742 LOG_ERROR("expected exactly one argument to presto_serial <serial-number>");
748 static const struct command_registration presto_command_handlers
[] = {
750 .name
= "presto_serial",
751 .handler
= presto_handle_serial_command
,
752 .mode
= COMMAND_CONFIG
,
753 .help
= "Configure USB serial number of Presto device.",
754 .usage
= "serial_string",
756 COMMAND_REGISTRATION_DONE
759 static int presto_jtag_init(void)
761 if (presto_open(presto_serial
) != ERROR_OK
)
764 if (presto_serial
!= NULL
)
765 LOG_ERROR("Cannot open PRESTO, serial number '%s'", presto_serial
);
767 LOG_ERROR("Cannot open PRESTO");
768 return ERROR_JTAG_INIT_FAILED
;
770 LOG_INFO("PRESTO open, serial number '%s'", presto
->serial
);
772 /* use JTAG speed setting from configuration file */
774 int retval
= jtag_get_speed(&jtag_speed_var
);
775 if (retval
!= ERROR_OK
)
777 presto_jtag_speed(jtag_speed_var
);
779 bitq_interface
= &presto_bitq
;
783 static int presto_jtag_quit(void)
787 LOG_INFO("PRESTO closed");
792 presto_serial
= NULL
;
798 struct jtag_interface presto_interface
= {
800 .commands
= presto_command_handlers
,
802 .execute_queue
= bitq_execute_queue
,
803 .speed
= presto_jtag_speed
,
804 .khz
= presto_adapter_khz
,
805 .speed_div
= presto_jtag_speed_div
,
806 .init
= presto_jtag_init
,
807 .quit
= presto_jtag_quit
,
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)