Encapsulate JTAG Cable API and interface structure, plan for new header file.
[openocd.git] / src / jtag / zy1000.c
1 /***************************************************************************
2 * Copyright (C) 2007-2008 by Øyvind Harboe *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #define INCLUDE_JTAG_MINIDRIVER_H
24 #define INCLUDE_JTAG_INTERFACE_H
25 #include "embeddedice.h"
26 #include "bitbang.h"
27
28 #include <cyg/hal/hal_io.h> // low level i/o
29 #include <cyg/hal/hal_diag.h>
30
31
32 #define ZYLIN_VERSION "1.52"
33 #define ZYLIN_DATE __DATE__
34 #define ZYLIN_TIME __TIME__
35 #define ZYLIN_OPENOCD "$Revision$"
36 #define ZYLIN_OPENOCD_VERSION "Zylin JTAG ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE " " ZYLIN_TIME
37 const char *zylin_config_dir="/config/settings";
38
39 /* low level command set
40 */
41 int zy1000_read(void);
42 static void zy1000_write(int tck, int tms, int tdi);
43 void zy1000_reset(int trst, int srst);
44
45
46 int zy1000_speed(int speed);
47 int zy1000_register_commands(struct command_context_s *cmd_ctx);
48 int zy1000_init(void);
49 int zy1000_quit(void);
50
51 /* interface commands */
52 int zy1000_handle_zy1000_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
53
54 static int zy1000_khz(int khz, int *jtag_speed)
55 {
56 if (khz==0)
57 {
58 *jtag_speed=0;
59 }
60 else
61 {
62 *jtag_speed=64000/khz;
63 }
64 return ERROR_OK;
65 }
66
67 static int zy1000_speed_div(int speed, int *khz)
68 {
69 if (speed==0)
70 {
71 *khz = 0;
72 }
73 else
74 {
75 *khz=64000/speed;
76 }
77
78 return ERROR_OK;
79 }
80
81 static bool readPowerDropout(void)
82 {
83 cyg_uint32 state;
84 // sample and clear power dropout
85 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x80);
86 HAL_READ_UINT32(ZY1000_JTAG_BASE+0x10, state);
87 bool powerDropout;
88 powerDropout = (state & 0x80) != 0;
89 return powerDropout;
90 }
91
92
93 static bool readSRST(void)
94 {
95 cyg_uint32 state;
96 // sample and clear SRST sensing
97 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x00000040);
98 HAL_READ_UINT32(ZY1000_JTAG_BASE+0x10, state);
99 bool srstAsserted;
100 srstAsserted = (state & 0x40) != 0;
101 return srstAsserted;
102 }
103
104 static int zy1000_srst_asserted(int *srst_asserted)
105 {
106 *srst_asserted=readSRST();
107 return ERROR_OK;
108 }
109
110 static int zy1000_power_dropout(int *dropout)
111 {
112 *dropout=readPowerDropout();
113 return ERROR_OK;
114 }
115
116
117 jtag_interface_t zy1000_interface =
118 {
119 .name = "ZY1000",
120 .execute_queue = bitbang_execute_queue,
121 .speed = zy1000_speed,
122 .register_commands = zy1000_register_commands,
123 .init = zy1000_init,
124 .quit = zy1000_quit,
125 .khz = zy1000_khz,
126 .speed_div = zy1000_speed_div,
127 .power_dropout = zy1000_power_dropout,
128 .srst_asserted = zy1000_srst_asserted,
129 };
130
131 bitbang_interface_t zy1000_bitbang =
132 {
133 .read = zy1000_read,
134 .write = zy1000_write,
135 .reset = zy1000_reset
136 };
137
138
139
140 static void zy1000_write(int tck, int tms, int tdi)
141 {
142
143 }
144
145 int zy1000_read(void)
146 {
147 return -1;
148 }
149
150 extern bool readSRST(void);
151
152 void zy1000_reset(int trst, int srst)
153 {
154 LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst);
155 if(!srst)
156 {
157 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x00000001);
158 }
159 else
160 {
161 /* Danger!!! if clk!=0 when in
162 * idle in TAP_IDLE, reset halt on str912 will fail.
163 */
164 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x00000001);
165 }
166
167 if(!trst)
168 {
169 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x00000002);
170 }
171 else
172 {
173 /* assert reset */
174 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x00000002);
175 }
176
177 if (trst||(srst&&(jtag_reset_config & RESET_SRST_PULLS_TRST)))
178 {
179 waitIdle();
180 /* we're now in the RESET state until trst is deasserted */
181 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, TAP_RESET);
182 } else
183 {
184 /* We'll get RCLK failure when we assert TRST, so clear any false positives here */
185 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x400);
186 }
187
188 /* wait for srst to float back up */
189 if (!srst)
190 {
191 int i;
192 for (i=0; i<1000; i++)
193 {
194 // We don't want to sense our own reset, so we clear here.
195 // There is of course a timing hole where we could loose
196 // a "real" reset.
197 if (!readSRST())
198 break;
199
200 /* wait 1ms */
201 alive_sleep(1);
202 }
203
204 if (i==1000)
205 {
206 LOG_USER("SRST didn't deassert after %dms", i);
207 } else if (i>1)
208 {
209 LOG_USER("SRST took %dms to deassert", i);
210 }
211 }
212 }
213
214 int zy1000_speed(int speed)
215 {
216 if(speed == 0)
217 {
218 /*0 means RCLK*/
219 speed = 0;
220 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x100);
221 LOG_DEBUG("jtag_speed using RCLK");
222 }
223 else
224 {
225 if(speed > 8190 || speed < 2)
226 {
227 LOG_USER("valid ZY1000 jtag_speed=[8190,2]. Divisor is 64MHz / even values between 8190-2, i.e. min 7814Hz, max 32MHz");
228 return ERROR_INVALID_ARGUMENTS;
229 }
230
231 LOG_USER("jtag_speed %d => JTAG clk=%f", speed, 64.0/(float)speed);
232 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x100);
233 ZY1000_POKE(ZY1000_JTAG_BASE+0x1c, speed&~1);
234 }
235 return ERROR_OK;
236 }
237
238 static bool savePower;
239
240
241 static void setPower(bool power)
242 {
243 savePower = power;
244 if (power)
245 {
246 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x14, 0x8);
247 } else
248 {
249 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x8);
250 }
251 }
252
253 int handle_power_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
254 {
255 if (argc > 1)
256 {
257 return ERROR_INVALID_ARGUMENTS;
258 }
259
260 if (argc == 1)
261 {
262 if (strcmp(args[0], "on") == 0)
263 {
264 setPower(1);
265 }
266 else if (strcmp(args[0], "off") == 0)
267 {
268 setPower(0);
269 } else
270 {
271 command_print(cmd_ctx, "arg is \"on\" or \"off\"");
272 return ERROR_INVALID_ARGUMENTS;
273 }
274 }
275
276 command_print(cmd_ctx, "Target power %s", savePower ? "on" : "off");
277
278 return ERROR_OK;
279 }
280
281
282 /* Give TELNET a way to find out what version this is */
283 static int jim_zy1000_version(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
284 {
285 if ((argc < 1) || (argc > 2))
286 return JIM_ERR;
287 char buff[128];
288 const char *version_str=NULL;
289
290 if (argc == 1)
291 {
292 version_str=ZYLIN_OPENOCD_VERSION;
293 } else
294 {
295 const char *str = Jim_GetString(argv[1], NULL);
296 if (strcmp("openocd", str) == 0)
297 {
298 int revision;
299 revision = atol(ZYLIN_OPENOCD+strlen("XRevision: "));
300 sprintf(buff, "%d", revision);
301 version_str=buff;
302 }
303 else if (strcmp("zy1000", str) == 0)
304 {
305 version_str=ZYLIN_VERSION;
306 }
307 else if (strcmp("date", str) == 0)
308 {
309 version_str=ZYLIN_DATE;
310 }
311 else
312 {
313 return JIM_ERR;
314 }
315 }
316
317 Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1));
318
319 return JIM_OK;
320 }
321
322
323 static int
324 zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp,
325 int argc,
326 Jim_Obj * const *argv)
327 {
328 if (argc != 1)
329 {
330 Jim_WrongNumArgs(interp, 1, argv, "powerstatus");
331 return JIM_ERR;
332 }
333
334 cyg_uint32 status;
335 ZY1000_PEEK(ZY1000_JTAG_BASE+0x10, status);
336
337 Jim_SetResult(interp, Jim_NewIntObj(interp, (status&0x80)!=0));
338
339 return JIM_OK;
340 }
341
342 int zy1000_register_commands(struct command_context_s *cmd_ctx)
343 {
344 register_command(cmd_ctx, NULL, "power", handle_power_command, COMMAND_ANY,
345 "power <on/off> - turn power switch to target on/off. No arguments - print status.");
346
347 Jim_CreateCommand(interp, "zy1000_version", jim_zy1000_version, NULL, NULL);
348
349
350 Jim_CreateCommand(interp, "powerstatus", zylinjtag_Jim_Command_powerstatus, NULL, NULL);
351
352 return ERROR_OK;
353 }
354
355
356
357
358 int zy1000_init(void)
359 {
360 LOG_USER("%s", ZYLIN_OPENOCD_VERSION);
361
362 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x30); // Turn on LED1 & LED2
363
364 setPower(true); // on by default
365
366
367 /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */
368 zy1000_reset(0, 0);
369 zy1000_speed(jtag_speed);
370
371 bitbang_interface = &zy1000_bitbang;
372
373 return ERROR_OK;
374 }
375
376 int zy1000_quit(void)
377 {
378
379 return ERROR_OK;
380 }
381
382
383
384
385 int interface_jtag_execute_queue(void)
386 {
387 cyg_uint32 empty;
388
389 waitIdle();
390 ZY1000_PEEK(ZY1000_JTAG_BASE+0x10, empty);
391 /* clear JTAG error register */
392 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x400);
393
394 if ((empty&0x400)!=0)
395 {
396 LOG_WARNING("RCLK timeout");
397 /* the error is informative only as we don't want to break the firmware if there
398 * is a false positive.
399 */
400 // return ERROR_FAIL;
401 }
402 return ERROR_OK;
403 }
404
405
406
407
408
409 static cyg_uint32 getShiftValue(void)
410 {
411 cyg_uint32 value;
412 waitIdle();
413 ZY1000_PEEK(ZY1000_JTAG_BASE+0xc, value);
414 VERBOSE(LOG_INFO("getShiftValue %08x", value));
415 return value;
416 }
417 #if 0
418 static cyg_uint32 getShiftValueFlip(void)
419 {
420 cyg_uint32 value;
421 waitIdle();
422 ZY1000_PEEK(ZY1000_JTAG_BASE+0x18, value);
423 VERBOSE(LOG_INFO("getShiftValue %08x (flipped)", value));
424 return value;
425 }
426 #endif
427
428 #if 0
429 static void shiftValueInnerFlip(const tap_state_t state, const tap_state_t endState, int repeat, cyg_uint32 value)
430 {
431 VERBOSE(LOG_INFO("shiftValueInner %s %s %d %08x (flipped)", tap_state_name(state), tap_state_name(endState), repeat, value));
432 cyg_uint32 a,b;
433 a=state;
434 b=endState;
435 ZY1000_POKE(ZY1000_JTAG_BASE+0xc, value);
436 ZY1000_POKE(ZY1000_JTAG_BASE+0x8, (1<<15)|(repeat<<8)|(a<<4)|b);
437 VERBOSE(getShiftValueFlip());
438 }
439 #endif
440
441 extern int jtag_check_value(u8 *captured, void *priv);
442
443 static void gotoEndState(void)
444 {
445 setCurrentState(cmd_queue_end_state);
446 }
447
448 static __inline void scanFields(int num_fields, scan_field_t *fields, tap_state_t shiftState, tap_state_t end_state)
449 {
450 int i;
451 int j;
452 int k;
453
454 for (i = 0; i < num_fields; i++)
455 {
456 cyg_uint32 value;
457
458 static u8 *in_buff=NULL; /* pointer to buffer for scanned data */
459 static int in_buff_size=0;
460 u8 *inBuffer=NULL;
461
462
463 // figure out where to store the input data
464 int num_bits=fields[i].num_bits;
465 if (fields[i].in_value!=NULL)
466 {
467 inBuffer=fields[i].in_value;
468 }
469
470 // here we shuffle N bits out/in
471 j=0;
472 while (j<num_bits)
473 {
474 tap_state_t pause_state;
475 int l;
476 k=num_bits-j;
477 pause_state=(shiftState==TAP_DRSHIFT)?TAP_DRSHIFT:TAP_IRSHIFT;
478 if (k>32)
479 {
480 k=32;
481 /* we have more to shift out */
482 } else if (i == num_fields-1)
483 {
484 /* this was the last to shift out this time */
485 pause_state=end_state;
486 }
487
488 // we have (num_bits+7)/8 bytes of bits to toggle out.
489 // bits are pushed out LSB to MSB
490 value=0;
491 if (fields[i].out_value!=NULL)
492 {
493 for (l=0; l<k; l+=8)
494 {
495 value|=fields[i].out_value[(j+l)/8]<<l;
496 }
497 }
498 /* mask away unused bits for easier debugging */
499 value&=~(((u32)0xffffffff)<<k);
500
501 shiftValueInner(shiftState, pause_state, k, value);
502
503 if (inBuffer!=NULL)
504 {
505 // data in, LSB to MSB
506 value=getShiftValue();
507 // we're shifting in data to MSB, shift data to be aligned for returning the value
508 value >>= 32-k;
509
510 for (l=0; l<k; l+=8)
511 {
512 inBuffer[(j+l)/8]=(value>>l)&0xff;
513 }
514 }
515 j+=k;
516 }
517 }
518 }
519
520 int interface_jtag_add_end_state(tap_state_t state)
521 {
522 return ERROR_OK;
523 }
524
525
526 int interface_jtag_add_ir_scan(int num_fields, scan_field_t *fields, tap_state_t state)
527 {
528
529 int j;
530 int scan_size = 0;
531 jtag_tap_t *tap, *nextTap;
532 for(tap = jtag_NextEnabledTap(NULL); tap!= NULL; tap=nextTap)
533 {
534 nextTap=jtag_NextEnabledTap(tap);
535 tap_state_t end_state;
536 if (nextTap==NULL)
537 {
538 end_state = cmd_queue_end_state;
539 } else
540 {
541 end_state = TAP_IRSHIFT;
542 }
543
544 int found = 0;
545
546 scan_size = tap->ir_length;
547
548 /* search the list */
549 for (j=0; j < num_fields; j++)
550 {
551 if (tap == fields[j].tap)
552 {
553 found = 1;
554
555 scanFields(1, fields+j, TAP_IRSHIFT, end_state);
556 /* update device information */
557 buf_cpy(fields[j].out_value, tap->cur_instr, scan_size);
558
559 tap->bypass = 0;
560 break;
561 }
562 }
563
564 if (!found)
565 {
566 /* if a device isn't listed, set it to BYPASS */
567 u8 ones[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
568
569 scan_field_t tmp;
570 memset(&tmp, 0, sizeof(tmp));
571 tmp.out_value = ones;
572 tmp.num_bits = scan_size;
573 scanFields(1, &tmp, TAP_IRSHIFT, end_state);
574 /* update device information */
575 buf_cpy(tmp.out_value, tap->cur_instr, scan_size);
576 tap->bypass = 1;
577 }
578 }
579
580 return ERROR_OK;
581 }
582
583
584
585
586
587 int interface_jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, tap_state_t state)
588 {
589 scanFields(num_fields, fields, TAP_IRSHIFT, cmd_queue_end_state);
590
591 return ERROR_OK;
592 }
593
594 /*extern jtag_command_t **jtag_get_last_command_p(void);*/
595
596 int interface_jtag_add_dr_scan(int num_fields, scan_field_t *fields, tap_state_t state)
597 {
598
599 int j;
600 jtag_tap_t *tap, *nextTap;
601 for(tap = jtag_NextEnabledTap(NULL); tap!= NULL; tap=nextTap)
602 {
603 nextTap=jtag_NextEnabledTap(tap);
604 int found=0;
605 tap_state_t end_state;
606 if (nextTap==NULL)
607 {
608 end_state = cmd_queue_end_state;
609 } else
610 {
611 end_state = TAP_DRSHIFT;
612 }
613
614 for (j=0; j < num_fields; j++)
615 {
616 if (tap == fields[j].tap)
617 {
618 found = 1;
619
620 scanFields(1, fields+j, TAP_DRSHIFT, end_state);
621 }
622 }
623 if (!found)
624 {
625 scan_field_t tmp;
626 /* program the scan field to 1 bit length, and ignore it's value */
627 tmp.num_bits = 1;
628 tmp.out_value = NULL;
629 tmp.in_value = NULL;
630
631 scanFields(1, &tmp, TAP_DRSHIFT, end_state);
632 }
633 else
634 {
635 }
636 }
637 return ERROR_OK;
638 }
639
640 int interface_jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, tap_state_t state)
641 {
642 scanFields(num_fields, fields, TAP_DRSHIFT, cmd_queue_end_state);
643 return ERROR_OK;
644 }
645
646
647 int interface_jtag_add_tlr()
648 {
649 setCurrentState(TAP_RESET);
650 return ERROR_OK;
651 }
652
653
654
655
656 extern int jtag_nsrst_delay;
657 extern int jtag_ntrst_delay;
658
659 int interface_jtag_add_reset(int req_trst, int req_srst)
660 {
661 zy1000_reset(req_trst, req_srst);
662 return ERROR_OK;
663 }
664
665 static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate)
666 {
667 /* num_cycles can be 0 */
668 setCurrentState(clockstate);
669
670 /* execute num_cycles, 32 at the time. */
671 int i;
672 for (i=0; i<num_cycles; i+=32)
673 {
674 int num;
675 num=32;
676 if (num_cycles-i<num)
677 {
678 num=num_cycles-i;
679 }
680 shiftValueInner(clockstate, clockstate, num, 0);
681 }
682
683 #if !TEST_MANUAL()
684 /* finish in end_state */
685 setCurrentState(state);
686 #else
687 tap_state_t t=TAP_IDLE;
688 /* test manual drive code on any target */
689 int tms;
690 u8 tms_scan = tap_get_tms_path(t, state);
691 int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
692
693 for (i = 0; i < tms_count; i++)
694 {
695 tms = (tms_scan >> i) & 1;
696 waitIdle();
697 ZY1000_POKE(ZY1000_JTAG_BASE+0x28, tms);
698 }
699 waitIdle();
700 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, state);
701 #endif
702
703
704 return ERROR_OK;
705 }
706
707 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
708 {
709 return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE);
710 }
711
712 int interface_jtag_add_clocks(int num_cycles)
713 {
714 return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_end_state);
715 }
716
717 int interface_jtag_add_sleep(u32 us)
718 {
719 jtag_sleep(us);
720 return ERROR_OK;
721 }
722
723 int interface_jtag_add_pathmove(int num_states, tap_state_t *path)
724 {
725 int state_count;
726 int tms = 0;
727
728 /*wait for the fifo to be empty*/
729 waitIdle();
730
731 state_count = 0;
732
733 tap_state_t cur_state=cmd_queue_cur_state;
734
735 while (num_states)
736 {
737 if (tap_state_transition(cur_state, false) == path[state_count])
738 {
739 tms = 0;
740 }
741 else if (tap_state_transition(cur_state, true) == path[state_count])
742 {
743 tms = 1;
744 }
745 else
746 {
747 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[state_count]));
748 exit(-1);
749 }
750
751 waitIdle();
752 ZY1000_POKE(ZY1000_JTAG_BASE+0x28, tms);
753
754 cur_state = path[state_count];
755 state_count++;
756 num_states--;
757 }
758
759 waitIdle();
760 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, cur_state);
761 return ERROR_OK;
762 }
763
764
765
766 void embeddedice_write_dcc(jtag_tap_t *tap, int reg_addr, u8 *buffer, int little, int count)
767 {
768 // static int const reg_addr=0x5;
769 tap_state_t end_state=cmd_queue_end_state;
770 if (jtag_NextEnabledTap(jtag_NextEnabledTap(NULL))==NULL)
771 {
772 /* better performance via code duplication */
773 if (little)
774 {
775 int i;
776 for (i = 0; i < count; i++)
777 {
778 shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 1));
779 shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr|(1<<5));
780 buffer+=4;
781 }
782 } else
783 {
784 int i;
785 for (i = 0; i < count; i++)
786 {
787 shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 0));
788 shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr|(1<<5));
789 buffer+=4;
790 }
791 }
792 }
793 else
794 {
795 int i;
796 for (i = 0; i < count; i++)
797 {
798 embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little));
799 buffer += 4;
800 }
801 }
802 }
803
804 int loadFile(const char *fileName, void **data, int *len);
805
806 /* boolean parameter stored on config */
807 int boolParam(char *var)
808 {
809 bool result = false;
810 char *name = alloc_printf("%s/%s", zylin_config_dir, var);
811 if (name == NULL)
812 return result;
813
814 void *data;
815 int len;
816 if (loadFile(name, &data, &len) == ERROR_OK)
817 {
818 if (len > 1)
819 len = 1;
820 result = strncmp((char *) data, "1", len) == 0;
821 free(data);
822 }
823 free(name);
824 return result;
825 }
826
827

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)