14dbf2ae71d982062e486a217f09a18075552b0b
[openocd.git] / src / pld / lattice.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2022 by Daniel Anselmi *
5 * danselmi@gmx.ch *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "lattice.h"
13 #include <jtag/jtag.h>
14 #include "pld.h"
15 #include "lattice_bit.h"
16 #include "ecp2_3.h"
17 #include "ecp5.h"
18 #include "certus.h"
19
20 #define PRELOAD 0x1C
21 #define USER1 0x32
22 #define USER2 0x38
23
24
25 struct lattice_devices_elem {
26 uint32_t id;
27 size_t preload_length;
28 enum lattice_family_e family;
29 };
30
31 static const struct lattice_devices_elem lattice_devices[] = {
32 {0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */},
33 {0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */},
34 {0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */},
35 {0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */},
36 {0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */},
37 {0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */},
38 {0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */},
39 {0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */},
40 {0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */},
41 {0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */},
42 {0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */},
43 {0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/},
44 {0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/},
45 {0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/},
46 {0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/},
47 {0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */},
48 {0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */},
49 {0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */},
50 {0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */},
51 {0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */},
52 {0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */},
53 {0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */},
54 {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */},
55 {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */},
56 {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */},
57 {0x310f0043, 362, LATTICE_CERTUS /* LFD2NX-17 */},
58 {0x310f1043, 362, LATTICE_CERTUS /* LFD2NX-40 */},
59 {0x010f4043, 362, LATTICE_CERTUS /* LFCPNX-100 */},
60 };
61
62 int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate)
63 {
64 struct scan_field field;
65 field.num_bits = tap->ir_length;
66 void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
67 if (!t) {
68 LOG_ERROR("Out of memory");
69 return ERROR_FAIL;
70 }
71 field.out_value = t;
72 buf_set_u32(t, 0, field.num_bits, new_instr);
73 field.in_value = NULL;
74 jtag_add_ir_scan(tap, &field, endstate);
75 free(t);
76 return ERROR_OK;
77 }
78
79 static int lattice_check_device_family(struct lattice_pld_device *lattice_device)
80 {
81 if (lattice_device->family != LATTICE_UNKNOWN && lattice_device->preload_length != 0)
82 return ERROR_OK;
83
84 if (!lattice_device->tap || !lattice_device->tap->hasidcode)
85 return ERROR_FAIL;
86
87 for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) {
88 if (lattice_devices[i].id == lattice_device->tap->idcode) {
89 if (lattice_device->family == LATTICE_UNKNOWN)
90 lattice_device->family = lattice_devices[i].family;
91 if (lattice_device->preload_length == 0)
92 lattice_device->preload_length = lattice_devices[i].preload_length;
93 return ERROR_OK;
94 }
95 }
96 LOG_ERROR("Unknown id! Specify family and preload-length manually.");
97 return ERROR_FAIL;
98 }
99
100 int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val,
101 uint32_t out_val, bool do_idle)
102 {
103 struct scan_field field;
104 uint8_t buffer[4];
105
106 int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
107 if (retval != ERROR_OK)
108 return retval;
109 if (do_idle) {
110 jtag_add_runtest(2, TAP_IDLE);
111 jtag_add_sleep(1000);
112 }
113
114 h_u32_to_le(buffer, out_val);
115 field.num_bits = 32;
116 field.out_value = buffer;
117 field.in_value = buffer;
118 jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
119 retval = jtag_execute_queue();
120 if (retval == ERROR_OK)
121 *in_val = le_to_h_u32(buffer);
122
123 return retval;
124 }
125
126 int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val,
127 uint64_t out_val)
128 {
129 struct scan_field field;
130 uint8_t buffer[8];
131
132 int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
133 if (retval != ERROR_OK)
134 return retval;
135 h_u64_to_le(buffer, out_val);
136 field.num_bits = 64;
137 field.out_value = buffer;
138 field.in_value = buffer;
139 jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
140 retval = jtag_execute_queue();
141 if (retval == ERROR_OK)
142 *in_val = le_to_h_u64(buffer);
143
144 return retval;
145 }
146
147 int lattice_preload(struct lattice_pld_device *lattice_device)
148 {
149 struct scan_field field;
150 size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8);
151
152 int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE);
153 if (retval != ERROR_OK)
154 return retval;
155 uint8_t *buffer = malloc(sz_bytes);
156 if (!buffer) {
157 LOG_ERROR("Out of memory");
158 return ERROR_FAIL;
159 }
160 memset(buffer, 0xff, sz_bytes);
161
162 field.num_bits = lattice_device->preload_length;
163 field.out_value = buffer;
164 field.in_value = NULL;
165 jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE);
166 retval = jtag_execute_queue();
167 free(buffer);
168 return retval;
169 }
170
171 static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint32_t *usercode, uint32_t out)
172 {
173 struct jtag_tap *tap = lattice_device->tap;
174 if (!tap)
175 return ERROR_FAIL;
176
177 if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
178 return lattice_ecp2_3_read_usercode(tap, usercode, out);
179 else if (lattice_device->family == LATTICE_ECP5)
180 return lattice_ecp5_read_usercode(tap, usercode, out);
181 else if (lattice_device->family == LATTICE_CERTUS)
182 return lattice_certus_read_usercode(tap, usercode, out);
183
184 return ERROR_FAIL;
185 }
186
187 int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out,
188 uint32_t expected, uint32_t mask)
189 {
190 uint32_t usercode;
191
192 int retval = lattice_read_usercode(lattice_device, &usercode, out);
193 if (retval != ERROR_OK)
194 return retval;
195
196 if ((usercode & mask) != expected) {
197 LOG_ERROR("verifying user code register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32,
198 usercode & mask, expected);
199 return ERROR_FAIL;
200 }
201 return ERROR_OK;
202 }
203
204 static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
205 {
206 if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
207 return lattice_ecp2_3_write_usercode(lattice_device, usercode);
208 else if (lattice_device->family == LATTICE_ECP5)
209 return lattice_ecp5_write_usercode(lattice_device, usercode);
210 else if (lattice_device->family == LATTICE_CERTUS)
211 return lattice_certus_write_usercode(lattice_device, usercode);
212
213 return ERROR_FAIL;
214 }
215
216 static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, uint32_t *status,
217 uint32_t out, bool do_idle)
218 {
219 if (!lattice_device->tap)
220 return ERROR_FAIL;
221
222 if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
223 return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle);
224 else if (lattice_device->family == LATTICE_ECP5)
225 return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle);
226
227 return ERROR_FAIL;
228 }
229 static int lattice_read_status_u64(struct lattice_pld_device *lattice_device, uint64_t *status,
230 uint64_t out)
231 {
232 if (!lattice_device->tap)
233 return ERROR_FAIL;
234
235 if (lattice_device->family == LATTICE_CERTUS)
236 return lattice_certus_read_status(lattice_device->tap, status, out);
237
238 return ERROR_FAIL;
239 }
240
241 int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out,
242 uint32_t expected, uint32_t mask, bool do_idle)
243 {
244 uint32_t status;
245 int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle);
246 if (retval != ERROR_OK)
247 return retval;
248
249 if ((status & mask) != expected) {
250 LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32,
251 status & mask, expected);
252 return ERROR_FAIL;
253 }
254 return ERROR_OK;
255 }
256
257 int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out,
258 uint64_t expected, uint64_t mask)
259 {
260 uint64_t status;
261 int retval = lattice_read_status_u64(lattice_device, &status, out);
262 if (retval != ERROR_OK)
263 return retval;
264
265 if ((status & mask) != expected) {
266 LOG_ERROR("verifying status register failed got: 0x%08" PRIx64 " expected: 0x%08" PRIx64,
267 status & mask, expected);
268 return ERROR_FAIL;
269 }
270 return ERROR_OK;
271 }
272
273 static int lattice_load_command(struct pld_device *pld_device, const char *filename)
274 {
275 if (!pld_device)
276 return ERROR_FAIL;
277
278 struct lattice_pld_device *lattice_device = pld_device->driver_priv;
279 if (!lattice_device || !lattice_device->tap)
280 return ERROR_FAIL;
281 struct jtag_tap *tap = lattice_device->tap;
282
283 if (!tap || !tap->hasidcode)
284 return ERROR_FAIL;
285
286 int retval = lattice_check_device_family(lattice_device);
287 if (retval != ERROR_OK)
288 return retval;
289
290 struct lattice_bit_file bit_file;
291 retval = lattice_read_file(&bit_file, filename, lattice_device->family);
292 if (retval != ERROR_OK)
293 return retval;
294
295 uint32_t id = tap->idcode;
296 retval = ERROR_FAIL;
297 switch (lattice_device->family) {
298 case LATTICE_ECP2:
299 retval = lattice_ecp2_load(lattice_device, &bit_file);
300 break;
301 case LATTICE_ECP3:
302 retval = lattice_ecp3_load(lattice_device, &bit_file);
303 break;
304 case LATTICE_ECP5:
305 case LATTICE_CERTUS:
306 if (bit_file.has_id && id != bit_file.idcode)
307 LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.",
308 id, bit_file.idcode);
309 if (lattice_device->family == LATTICE_ECP5)
310 retval = lattice_ecp5_load(lattice_device, &bit_file);
311 else
312 retval = lattice_certus_load(lattice_device, &bit_file);
313 break;
314 default:
315 LOG_ERROR("loading unknown device family");
316 break;
317 }
318 free(bit_file.raw_bit.data);
319 return retval;
320 }
321
322 static int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub)
323 {
324 if (!pld_device)
325 return ERROR_FAIL;
326
327 struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
328
329 if (!pld_device_info || !pld_device_info->tap)
330 return ERROR_FAIL;
331
332 hub->tap = pld_device_info->tap;
333
334 if (user_num == 1) {
335 hub->user_ir_code = USER1;
336 } else if (user_num == 2) {
337 hub->user_ir_code = USER2;
338 } else {
339 LOG_ERROR("lattice devices only have user register 1 & 2");
340 return ERROR_FAIL;
341 }
342 return ERROR_OK;
343 }
344
345 static int lattice_connect_spi_to_jtag(struct pld_device *pld_device)
346 {
347 if (!pld_device)
348 return ERROR_FAIL;
349
350 struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
351
352 int retval = lattice_check_device_family(pld_device_info);
353 if (retval != ERROR_OK)
354 return retval;
355
356 if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3)
357 return lattice_ecp2_3_connect_spi_to_jtag(pld_device_info);
358 else if (pld_device_info->family == LATTICE_ECP5)
359 return lattice_ecp5_connect_spi_to_jtag(pld_device_info);
360
361 return ERROR_FAIL;
362 }
363
364 static int lattice_disconnect_spi_from_jtag(struct pld_device *pld_device)
365 {
366 if (!pld_device)
367 return ERROR_FAIL;
368
369 struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
370
371 int retval = lattice_check_device_family(pld_device_info);
372 if (retval != ERROR_OK)
373 return retval;
374
375 if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3)
376 return lattice_ecp2_3_disconnect_spi_from_jtag(pld_device_info);
377 else if (pld_device_info->family == LATTICE_ECP5)
378 return lattice_ecp5_disconnect_spi_from_jtag(pld_device_info);
379
380 return ERROR_FAIL;
381 }
382
383 static int lattice_get_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits,
384 unsigned int *trailing_write_bits)
385 {
386 if (!pld_device)
387 return ERROR_FAIL;
388
389 struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
390
391 int retval = lattice_check_device_family(pld_device_info);
392 if (retval != ERROR_OK)
393 return retval;
394
395 if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3)
396 return lattice_ecp2_3_get_facing_read_bits(pld_device_info, facing_read_bits);
397 else if (pld_device_info->family == LATTICE_ECP5)
398 return lattice_ecp5_get_facing_read_bits(pld_device_info, facing_read_bits);
399
400 return ERROR_FAIL;
401 }
402
403 static int lattice_has_jtagspi_instruction(struct pld_device *device, bool *has_instruction)
404 {
405 *has_instruction = true;
406 return ERROR_OK;
407 }
408
409 PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command)
410 {
411 if (CMD_ARGC != 4 && CMD_ARGC != 6)
412 return ERROR_COMMAND_SYNTAX_ERROR;
413
414 if (strcmp(CMD_ARGV[2], "-chain-position") != 0)
415 return ERROR_COMMAND_SYNTAX_ERROR;
416
417 struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]);
418 if (!tap) {
419 command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]);
420 return ERROR_FAIL;
421 }
422
423 /* id is not known yet -> postpone lattice_check_device_family() */
424 enum lattice_family_e family = LATTICE_UNKNOWN;
425 if (CMD_ARGC == 6) {
426 if (strcmp(CMD_ARGV[4], "-family") != 0)
427 return ERROR_COMMAND_SYNTAX_ERROR;
428
429 if (strcasecmp(CMD_ARGV[5], "ecp2") == 0) {
430 family = LATTICE_ECP2;
431 } else if (strcasecmp(CMD_ARGV[5], "ecp3") == 0) {
432 family = LATTICE_ECP3;
433 } else if (strcasecmp(CMD_ARGV[5], "ecp5") == 0) {
434 family = LATTICE_ECP5;
435 } else if (strcasecmp(CMD_ARGV[5], "certus") == 0) {
436 family = LATTICE_CERTUS;
437 } else {
438 command_print(CMD, "unknown family");
439 return ERROR_FAIL;
440 }
441 }
442
443 struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device));
444 if (!lattice_device) {
445 LOG_ERROR("Out of memory");
446 return ERROR_FAIL;
447 }
448
449 lattice_device->tap = tap;
450 lattice_device->family = family;
451 lattice_device->preload_length = 0;
452
453 pld->driver_priv = lattice_device;
454
455 return ERROR_OK;
456 }
457
458 COMMAND_HANDLER(lattice_read_usercode_register_command_handler)
459 {
460 uint32_t usercode;
461
462 if (CMD_ARGC != 1)
463 return ERROR_COMMAND_SYNTAX_ERROR;
464
465 struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
466 if (!device) {
467 command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
468 return ERROR_FAIL;
469 }
470
471 struct lattice_pld_device *lattice_device = device->driver_priv;
472 if (!lattice_device)
473 return ERROR_FAIL;
474
475 int retval = lattice_check_device_family(lattice_device);
476 if (retval != ERROR_OK)
477 return retval;
478
479 retval = lattice_read_usercode(lattice_device, &usercode, 0x0);
480 if (retval == ERROR_OK)
481 command_print(CMD, "0x%8.8" PRIx32, usercode);
482
483 return retval;
484 }
485
486 COMMAND_HANDLER(lattice_set_preload_command_handler)
487 {
488 unsigned int preload_length;
489
490 if (CMD_ARGC != 2)
491 return ERROR_COMMAND_SYNTAX_ERROR;
492
493 struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
494 if (!device) {
495 command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
496 return ERROR_FAIL;
497 }
498
499 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length);
500
501 struct lattice_pld_device *lattice_device = device->driver_priv;
502
503 if (!lattice_device)
504 return ERROR_FAIL;
505
506 lattice_device->preload_length = preload_length;
507
508 return ERROR_OK;
509 }
510
511 COMMAND_HANDLER(lattice_write_usercode_register_command_handler)
512 {
513 uint32_t usercode;
514
515 if (CMD_ARGC != 2)
516 return ERROR_COMMAND_SYNTAX_ERROR;
517
518 struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
519 if (!device) {
520 command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
521 return ERROR_FAIL;
522 }
523
524 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode);
525
526 struct lattice_pld_device *lattice_device = device->driver_priv;
527 if (!lattice_device)
528 return ERROR_FAIL;
529
530 int retval = lattice_check_device_family(lattice_device);
531 if (retval != ERROR_OK)
532 return retval;
533
534 return lattice_write_usercode(lattice_device, usercode);
535 }
536
537 COMMAND_HANDLER(lattice_read_status_command_handler)
538 {
539 if (CMD_ARGC != 1)
540 return ERROR_COMMAND_SYNTAX_ERROR;
541
542 struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
543 if (!device) {
544 command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
545 return ERROR_FAIL;
546 }
547
548 struct lattice_pld_device *lattice_device = device->driver_priv;
549 if (!lattice_device)
550 return ERROR_FAIL;
551
552 int retval = lattice_check_device_family(lattice_device);
553 if (retval != ERROR_OK)
554 return retval;
555
556 if (lattice_device->family == LATTICE_CERTUS) {
557 uint64_t status;
558 retval = lattice_read_status_u64(lattice_device, &status, 0x0);
559 if (retval == ERROR_OK)
560 command_print(CMD, "0x%016" PRIx64, status);
561 } else {
562 uint32_t status;
563 const bool do_idle = lattice_device->family == LATTICE_ECP5;
564 retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle);
565 if (retval == ERROR_OK)
566 command_print(CMD, "0x%8.8" PRIx32, status);
567 }
568
569 return retval;
570 }
571
572 static const struct command_registration lattice_exec_command_handlers[] = {
573 {
574 .name = "read_status",
575 .mode = COMMAND_EXEC,
576 .handler = lattice_read_status_command_handler,
577 .help = "reading status register from FPGA",
578 .usage = "pld_name",
579 }, {
580 .name = "read_user",
581 .mode = COMMAND_EXEC,
582 .handler = lattice_read_usercode_register_command_handler,
583 .help = "reading usercode register from FPGA",
584 .usage = "pld_name",
585 }, {
586 .name = "write_user",
587 .mode = COMMAND_EXEC,
588 .handler = lattice_write_usercode_register_command_handler,
589 .help = "writing usercode register to FPGA",
590 .usage = "pld_name value",
591 }, {
592 .name = "set_preload",
593 .mode = COMMAND_ANY,
594 .handler = lattice_set_preload_command_handler,
595 .help = "set length for preload (device specific)",
596 .usage = "pld_name value",
597 },
598 COMMAND_REGISTRATION_DONE
599 };
600
601 static const struct command_registration lattice_command_handler[] = {
602 {
603 .name = "lattice",
604 .mode = COMMAND_ANY,
605 .help = "lattice specific commands",
606 .usage = "",
607 .chain = lattice_exec_command_handlers,
608 },
609 COMMAND_REGISTRATION_DONE
610 };
611
612 struct pld_driver lattice_pld = {
613 .name = "lattice",
614 .commands = lattice_command_handler,
615 .pld_create_command = &lattice_pld_create_command,
616 .load = &lattice_load_command,
617 .get_ipdbg_hub = lattice_get_ipdbg_hub,
618 .has_jtagspi_instruction = lattice_has_jtagspi_instruction,
619 .connect_spi_to_jtag = lattice_connect_spi_to_jtag,
620 .disconnect_spi_from_jtag = lattice_disconnect_spi_from_jtag,
621 .get_stuff_bits = lattice_get_stuff_bits,
622 };

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)