4852a56f56ca9cc056446d3a2f9403c0266ccf91
[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_INTERFACE_H
24 #include "embeddedice.h"
25 #include "minidriver.h"
26 #include "interface.h"
27 #include "bitbang.h"
28
29 #include <cyg/hal/hal_io.h> // low level i/o
30 #include <cyg/hal/hal_diag.h>
31
32
33 #define ZYLIN_VERSION "1.52"
34 #define ZYLIN_DATE __DATE__
35 #define ZYLIN_TIME __TIME__
36 #define ZYLIN_OPENOCD "$Revision$"
37 #define ZYLIN_OPENOCD_VERSION "Zylin JTAG ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE " " ZYLIN_TIME
38 const char *zylin_config_dir="/config/settings";
39
40 /* low level command set
41 */
42 int zy1000_read(void);
43 static void zy1000_write(int tck, int tms, int tdi);
44 void zy1000_reset(int trst, int srst);
45
46
47 int zy1000_speed(int speed);
48 int zy1000_register_commands(struct command_context_s *cmd_ctx);
49 int zy1000_init(void);
50 int zy1000_quit(void);
51
52 /* interface commands */
53 int zy1000_handle_zy1000_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
54
55 static int zy1000_khz(int khz, int *jtag_speed)
56 {
57 if (khz==0)
58 {
59 *jtag_speed=0;
60 }
61 else
62 {
63 *jtag_speed=64000/khz;
64 }
65 return ERROR_OK;
66 }
67
68 static int zy1000_speed_div(int speed, int *khz)
69 {
70 if (speed==0)
71 {
72 *khz = 0;
73 }
74 else
75 {
76 *khz=64000/speed;
77 }
78
79 return ERROR_OK;
80 }
81
82 static bool readPowerDropout(void)
83 {
84 cyg_uint32 state;
85 // sample and clear power dropout
86 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x80);
87 HAL_READ_UINT32(ZY1000_JTAG_BASE+0x10, state);
88 bool powerDropout;
89 powerDropout = (state & 0x80) != 0;
90 return powerDropout;
91 }
92
93
94 static bool readSRST(void)
95 {
96 cyg_uint32 state;
97 // sample and clear SRST sensing
98 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x00000040);
99 HAL_READ_UINT32(ZY1000_JTAG_BASE+0x10, state);
100 bool srstAsserted;
101 srstAsserted = (state & 0x40) != 0;
102 return srstAsserted;
103 }
104
105 static int zy1000_srst_asserted(int *srst_asserted)
106 {
107 *srst_asserted=readSRST();
108 return ERROR_OK;
109 }
110
111 static int zy1000_power_dropout(int *dropout)
112 {
113 *dropout=readPowerDropout();
114 return ERROR_OK;
115 }
116
117
118 jtag_interface_t zy1000_interface =
119 {
120 .name = "ZY1000",
121 .execute_queue = bitbang_execute_queue,
122 .speed = zy1000_speed,
123 .register_commands = zy1000_register_commands,
124 .init = zy1000_init,
125 .quit = zy1000_quit,
126 .khz = zy1000_khz,
127 .speed_div = zy1000_speed_div,
128 .power_dropout = zy1000_power_dropout,
129 .srst_asserted = zy1000_srst_asserted,
130 };
131
132 bitbang_interface_t zy1000_bitbang =
133 {
134 .read = zy1000_read,
135 .write = zy1000_write,
136 .reset = zy1000_reset
137 };
138
139
140
141 static void zy1000_write(int tck, int tms, int tdi)
142 {
143
144 }
145
146 int zy1000_read(void)
147 {
148 return -1;
149 }
150
151 extern bool readSRST(void);
152
153 void zy1000_reset(int trst, int srst)
154 {
155 LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst);
156 if(!srst)
157 {
158 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x00000001);
159 }
160 else
161 {
162 /* Danger!!! if clk!=0 when in
163 * idle in TAP_IDLE, reset halt on str912 will fail.
164 */
165 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x00000001);
166 }
167
168 if(!trst)
169 {
170 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x00000002);
171 }
172 else
173 {
174 /* assert reset */
175 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x00000002);
176 }
177
178 if (trst||(srst&&(jtag_reset_config & RESET_SRST_PULLS_TRST)))
179 {
180 waitIdle();
181 /* we're now in the RESET state until trst is deasserted */
182 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, TAP_RESET);
183 } else
184 {
185 /* We'll get RCLK failure when we assert TRST, so clear any false positives here */
186 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x400);
187 }
188
189 /* wait for srst to float back up */
190 if (!srst)
191 {
192 int i;
193 for (i=0; i<1000; i++)
194 {
195 // We don't want to sense our own reset, so we clear here.
196 // There is of course a timing hole where we could loose
197 // a "real" reset.
198 if (!readSRST())
199 break;
200
201 /* wait 1ms */
202 alive_sleep(1);
203 }
204
205 if (i==1000)
206 {
207 LOG_USER("SRST didn't deassert after %dms", i);
208 } else if (i>1)
209 {
210 LOG_USER("SRST took %dms to deassert", i);
211 }
212 }
213 }
214
215 int zy1000_speed(int speed)
216 {
217 if(speed == 0)
218 {
219 /*0 means RCLK*/
220 speed = 0;
221 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x100);
222 LOG_DEBUG("jtag_speed using RCLK");
223 }
224 else
225 {
226 if(speed > 8190 || speed < 2)
227 {
228 LOG_USER("valid ZY1000 jtag_speed=[8190,2]. Divisor is 64MHz / even values between 8190-2, i.e. min 7814Hz, max 32MHz");
229 return ERROR_INVALID_ARGUMENTS;
230 }
231
232 LOG_USER("jtag_speed %d => JTAG clk=%f", speed, 64.0/(float)speed);
233 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x100);
234 ZY1000_POKE(ZY1000_JTAG_BASE+0x1c, speed&~1);
235 }
236 return ERROR_OK;
237 }
238
239 static bool savePower;
240
241
242 static void setPower(bool power)
243 {
244 savePower = power;
245 if (power)
246 {
247 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x14, 0x8);
248 } else
249 {
250 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x8);
251 }
252 }
253
254 int handle_power_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
255 {
256 if (argc > 1)
257 {
258 return ERROR_INVALID_ARGUMENTS;
259 }
260
261 if (argc == 1)
262 {
263 if (strcmp(args[0], "on") == 0)
264 {
265 setPower(1);
266 }
267 else if (strcmp(args[0], "off") == 0)
268 {
269 setPower(0);
270 } else
271 {
272 command_print(cmd_ctx, "arg is \"on\" or \"off\"");
273 return ERROR_INVALID_ARGUMENTS;
274 }
275 }
276
277 command_print(cmd_ctx, "Target power %s", savePower ? "on" : "off");
278
279 return ERROR_OK;
280 }
281
282
283 /* Give TELNET a way to find out what version this is */
284 static int jim_zy1000_version(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
285 {
286 if ((argc < 1) || (argc > 2))
287 return JIM_ERR;
288 char buff[128];
289 const char *version_str=NULL;
290
291 if (argc == 1)
292 {
293 version_str=ZYLIN_OPENOCD_VERSION;
294 } else
295 {
296 const char *str = Jim_GetString(argv[1], NULL);
297 if (strcmp("openocd", str) == 0)
298 {
299 int revision;
300 revision = atol(ZYLIN_OPENOCD+strlen("XRevision: "));
301 sprintf(buff, "%d", revision);
302 version_str=buff;
303 }
304 else if (strcmp("zy1000", str) == 0)
305 {
306 version_str=ZYLIN_VERSION;
307 }
308 else if (strcmp("date", str) == 0)
309 {
310 version_str=ZYLIN_DATE;
311 }
312 else
313 {
314 return JIM_ERR;
315 }
316 }
317
318 Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1));
319
320 return JIM_OK;
321 }
322
323
324 static int
325 zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp,
326 int argc,
327 Jim_Obj * const *argv)
328 {
329 if (argc != 1)
330 {
331 Jim_WrongNumArgs(interp, 1, argv, "powerstatus");
332 return JIM_ERR;
333 }
334
335 cyg_uint32 status;
336 ZY1000_PEEK(ZY1000_JTAG_BASE+0x10, status);
337
338 Jim_SetResult(interp, Jim_NewIntObj(interp, (status&0x80)!=0));
339
340 return JIM_OK;
341 }
342
343 int zy1000_register_commands(struct command_context_s *cmd_ctx)
344 {
345 register_command(cmd_ctx, NULL, "power", handle_power_command, COMMAND_ANY,
346 "power <on/off> - turn power switch to target on/off. No arguments - print status.");
347
348 Jim_CreateCommand(interp, "zy1000_version", jim_zy1000_version, NULL, NULL);
349
350
351 Jim_CreateCommand(interp, "powerstatus", zylinjtag_Jim_Command_powerstatus, NULL, NULL);
352
353 return ERROR_OK;
354 }
355
356
357
358
359 int zy1000_init(void)
360 {
361 LOG_USER("%s", ZYLIN_OPENOCD_VERSION);
362
363 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x30); // Turn on LED1 & LED2
364
365 setPower(true); // on by default
366
367
368 /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */
369 zy1000_reset(0, 0);
370 zy1000_speed(jtag_speed);
371
372 bitbang_interface = &zy1000_bitbang;
373
374 return ERROR_OK;
375 }
376
377 int zy1000_quit(void)
378 {
379
380 return ERROR_OK;
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, const 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, const 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, const 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, const 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, const 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)