arm_coresight: define ARM_CS_CIDR_CLASS()
[openocd.git] / src / target / armv7a.c
1 /***************************************************************************
2 * Copyright (C) 2009 by David Brownell *
3 * *
4 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <helper/replacements.h>
25
26 #include "armv7a.h"
27 #include "armv7a_mmu.h"
28 #include "arm_disassembler.h"
29
30 #include "register.h"
31 #include <helper/binarybuffer.h>
32 #include <helper/command.h>
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "arm_opcodes.h"
39 #include "target.h"
40 #include "target_type.h"
41 #include "smp.h"
42
43 static void armv7a_show_fault_registers(struct target *target)
44 {
45 uint32_t dfsr, ifsr, dfar, ifar;
46 struct armv7a_common *armv7a = target_to_armv7a(target);
47 struct arm_dpm *dpm = armv7a->arm.dpm;
48 int retval;
49
50 retval = dpm->prepare(dpm);
51 if (retval != ERROR_OK)
52 return;
53
54 /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */
55
56 /* c5/c0 - {data, instruction} fault status registers */
57 retval = dpm->instr_read_data_r0(dpm,
58 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
59 &dfsr);
60 if (retval != ERROR_OK)
61 goto done;
62
63 retval = dpm->instr_read_data_r0(dpm,
64 ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
65 &ifsr);
66 if (retval != ERROR_OK)
67 goto done;
68
69 /* c6/c0 - {data, instruction} fault address registers */
70 retval = dpm->instr_read_data_r0(dpm,
71 ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
72 &dfar);
73 if (retval != ERROR_OK)
74 goto done;
75
76 retval = dpm->instr_read_data_r0(dpm,
77 ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
78 &ifar);
79 if (retval != ERROR_OK)
80 goto done;
81
82 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
83 ", DFAR: %8.8" PRIx32, dfsr, dfar);
84 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
85 ", IFAR: %8.8" PRIx32, ifsr, ifar);
86
87 done:
88 /* (void) */ dpm->finish(dpm);
89 }
90
91
92 /* retrieve main id register */
93 static int armv7a_read_midr(struct target *target)
94 {
95 int retval = ERROR_FAIL;
96 struct armv7a_common *armv7a = target_to_armv7a(target);
97 struct arm_dpm *dpm = armv7a->arm.dpm;
98 uint32_t midr;
99 retval = dpm->prepare(dpm);
100 if (retval != ERROR_OK)
101 goto done;
102 /* MRC p15,0,<Rd>,c0,c0,0; read main id register*/
103
104 retval = dpm->instr_read_data_r0(dpm,
105 ARMV4_5_MRC(15, 0, 0, 0, 0, 0),
106 &midr);
107 if (retval != ERROR_OK)
108 goto done;
109
110 armv7a->rev = (midr & 0xf);
111 armv7a->partnum = (midr >> 4) & 0xfff;
112 armv7a->arch = (midr >> 16) & 0xf;
113 armv7a->variant = (midr >> 20) & 0xf;
114 armv7a->implementor = (midr >> 24) & 0xff;
115 LOG_INFO("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
116 ", variant %" PRIx32 ", implementor %" PRIx32,
117 target->cmd_name,
118 armv7a->rev,
119 armv7a->partnum,
120 armv7a->arch,
121 armv7a->variant,
122 armv7a->implementor);
123
124 done:
125 dpm->finish(dpm);
126 return retval;
127 }
128
129 int armv7a_read_ttbcr(struct target *target)
130 {
131 struct armv7a_common *armv7a = target_to_armv7a(target);
132 struct arm_dpm *dpm = armv7a->arm.dpm;
133 uint32_t ttbcr, ttbcr_n;
134 int ttbidx;
135 int retval;
136
137 retval = dpm->prepare(dpm);
138 if (retval != ERROR_OK)
139 goto done;
140
141 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
142 retval = dpm->instr_read_data_r0(dpm,
143 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
144 &ttbcr);
145 if (retval != ERROR_OK)
146 goto done;
147
148 LOG_DEBUG("ttbcr %" PRIx32, ttbcr);
149
150 ttbcr_n = ttbcr & 0x7;
151 armv7a->armv7a_mmu.ttbcr = ttbcr;
152 armv7a->armv7a_mmu.cached = 1;
153
154 for (ttbidx = 0; ttbidx < 2; ttbidx++) {
155 /* MRC p15,0,<Rt>,c2,c0,ttbidx */
156 retval = dpm->instr_read_data_r0(dpm,
157 ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx),
158 &armv7a->armv7a_mmu.ttbr[ttbidx]);
159 if (retval != ERROR_OK)
160 goto done;
161 }
162
163 /*
164 * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
165 * document # ARM DDI 0406C
166 */
167 armv7a->armv7a_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n;
168 armv7a->armv7a_mmu.ttbr_range[1] = 0xffffffff;
169 armv7a->armv7a_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n);
170 armv7a->armv7a_mmu.ttbr_mask[1] = 0xffffffff << 14;
171 armv7a->armv7a_mmu.cached = 1;
172
173 retval = armv7a_read_midr(target);
174 if (retval != ERROR_OK)
175 goto done;
176
177 /* FIXME: why this special case based on part number? */
178 if ((armv7a->partnum & 0xf) == 0) {
179 /* ARM DDI 0344H , ARM DDI 0407F */
180 armv7a->armv7a_mmu.ttbr_mask[0] = 7 << (32 - ttbcr_n);
181 }
182
183 LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32,
184 (ttbcr_n != 0) ? "used" : "not used",
185 armv7a->armv7a_mmu.ttbr_mask[0],
186 armv7a->armv7a_mmu.ttbr_mask[1]);
187
188 done:
189 dpm->finish(dpm);
190 return retval;
191 }
192
193 /* FIXME: remove it */
194 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
195 {
196 struct armv7a_l2x_cache *l2x_cache;
197 struct target_list *head;
198
199 struct armv7a_common *armv7a = target_to_armv7a(target);
200 l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
201 l2x_cache->base = base;
202 l2x_cache->way = way;
203 /*LOG_INFO("cache l2 initialized base %x way %d",
204 l2x_cache->base,l2x_cache->way);*/
205 if (armv7a->armv7a_mmu.armv7a_cache.outer_cache)
206 LOG_INFO("outer cache already initialized\n");
207 armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
208 /* initialize all target in this cluster (smp target)
209 * l2 cache must be configured after smp declaration */
210 foreach_smp_target(head, target->smp_targets) {
211 struct target *curr = head->target;
212 if (curr != target) {
213 armv7a = target_to_armv7a(curr);
214 if (armv7a->armv7a_mmu.armv7a_cache.outer_cache)
215 LOG_ERROR("smp target : outer cache already initialized\n");
216 armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
217 }
218 }
219 return JIM_OK;
220 }
221
222 /* FIXME: remove it */
223 COMMAND_HANDLER(handle_cache_l2x)
224 {
225 struct target *target = get_current_target(CMD_CTX);
226 uint32_t base, way;
227
228 if (CMD_ARGC != 2)
229 return ERROR_COMMAND_SYNTAX_ERROR;
230
231 /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
232 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
233 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
234
235 /* AP address is in bits 31:24 of DP_SELECT */
236 armv7a_l2x_cache_init(target, base, way);
237
238 return ERROR_OK;
239 }
240
241 int armv7a_handle_cache_info_command(struct command_invocation *cmd,
242 struct armv7a_cache_common *armv7a_cache)
243 {
244 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
245 (armv7a_cache->outer_cache);
246
247 int cl;
248
249 if (armv7a_cache->info == -1) {
250 command_print(cmd, "cache not yet identified");
251 return ERROR_OK;
252 }
253
254 for (cl = 0; cl < armv7a_cache->loc; cl++) {
255 struct armv7a_arch_cache *arch = &(armv7a_cache->arch[cl]);
256
257 if (arch->ctype & 1) {
258 command_print(cmd,
259 "L%d I-Cache: linelen %" PRIu32
260 ", associativity %" PRIu32
261 ", nsets %" PRIu32
262 ", cachesize %" PRIu32 " KBytes",
263 cl+1,
264 arch->i_size.linelen,
265 arch->i_size.associativity,
266 arch->i_size.nsets,
267 arch->i_size.cachesize);
268 }
269
270 if (arch->ctype >= 2) {
271 command_print(cmd,
272 "L%d D-Cache: linelen %" PRIu32
273 ", associativity %" PRIu32
274 ", nsets %" PRIu32
275 ", cachesize %" PRIu32 " KBytes",
276 cl+1,
277 arch->d_u_size.linelen,
278 arch->d_u_size.associativity,
279 arch->d_u_size.nsets,
280 arch->d_u_size.cachesize);
281 }
282 }
283
284 if (l2x_cache)
285 command_print(cmd, "Outer unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways",
286 l2x_cache->base, l2x_cache->way);
287
288 return ERROR_OK;
289 }
290
291 /* retrieve core id cluster id */
292 static int armv7a_read_mpidr(struct target *target)
293 {
294 int retval = ERROR_FAIL;
295 struct armv7a_common *armv7a = target_to_armv7a(target);
296 struct arm_dpm *dpm = armv7a->arm.dpm;
297 uint32_t mpidr;
298 retval = dpm->prepare(dpm);
299 if (retval != ERROR_OK)
300 goto done;
301 /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
302
303 retval = dpm->instr_read_data_r0(dpm,
304 ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
305 &mpidr);
306 if (retval != ERROR_OK)
307 goto done;
308
309 /* Is register in Multiprocessing Extensions register format? */
310 if (mpidr & MPIDR_MP_EXT) {
311 LOG_DEBUG("%s: MPIDR 0x%" PRIx32, target_name(target), mpidr);
312 armv7a->multi_processor_system = (mpidr >> 30) & 1;
313 armv7a->multi_threading_processor = (mpidr >> 24) & 1;
314 armv7a->level2_id = (mpidr >> 16) & 0xf;
315 armv7a->cluster_id = (mpidr >> 8) & 0xf;
316 armv7a->cpu_id = mpidr & 0xf;
317 LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s",
318 target_name(target),
319 armv7a->level2_id,
320 armv7a->cluster_id,
321 armv7a->cpu_id,
322 armv7a->multi_processor_system == 0 ? "multi core" : "mono core",
323 armv7a->multi_threading_processor == 1 ? "SMT" : "no SMT");
324
325 } else
326 LOG_ERROR("MPIDR not in multiprocessor format");
327
328 done:
329 dpm->finish(dpm);
330 return retval;
331
332
333 }
334
335 static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg)
336 {
337 int retval = ERROR_OK;
338
339 /* select cache level */
340 retval = dpm->instr_write_data_r0(dpm,
341 ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
342 (cl << 1) | (ct == 1 ? 1 : 0));
343 if (retval != ERROR_OK)
344 goto done;
345
346 retval = dpm->instr_read_data_r0(dpm,
347 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
348 cache_reg);
349 done:
350 return retval;
351 }
352
353 static struct armv7a_cachesize decode_cache_reg(uint32_t cache_reg)
354 {
355 struct armv7a_cachesize size;
356 int i = 0;
357
358 size.linelen = 16 << (cache_reg & 0x7);
359 size.associativity = ((cache_reg >> 3) & 0x3ff) + 1;
360 size.nsets = ((cache_reg >> 13) & 0x7fff) + 1;
361 size.cachesize = size.linelen * size.associativity * size.nsets / 1024;
362
363 /* compute info for set way operation on cache */
364 size.index_shift = (cache_reg & 0x7) + 4;
365 size.index = (cache_reg >> 13) & 0x7fff;
366 size.way = ((cache_reg >> 3) & 0x3ff);
367
368 while (((size.way << i) & 0x80000000) == 0)
369 i++;
370 size.way_shift = i;
371
372 return size;
373 }
374
375 int armv7a_identify_cache(struct target *target)
376 {
377 /* read cache descriptor */
378 int retval = ERROR_FAIL;
379 struct armv7a_common *armv7a = target_to_armv7a(target);
380 struct arm_dpm *dpm = armv7a->arm.dpm;
381 uint32_t csselr, clidr, ctr;
382 uint32_t cache_reg;
383 int cl, ctype;
384 struct armv7a_cache_common *cache =
385 &(armv7a->armv7a_mmu.armv7a_cache);
386
387 retval = dpm->prepare(dpm);
388 if (retval != ERROR_OK)
389 goto done;
390
391 /* retrieve CTR
392 * mrc p15, 0, r0, c0, c0, 1 @ read ctr */
393 retval = dpm->instr_read_data_r0(dpm,
394 ARMV4_5_MRC(15, 0, 0, 0, 0, 1),
395 &ctr);
396 if (retval != ERROR_OK)
397 goto done;
398
399 cache->iminline = 4UL << (ctr & 0xf);
400 cache->dminline = 4UL << ((ctr & 0xf0000) >> 16);
401 LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32,
402 ctr, cache->iminline, cache->dminline);
403
404 /* retrieve CLIDR
405 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
406 retval = dpm->instr_read_data_r0(dpm,
407 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
408 &clidr);
409 if (retval != ERROR_OK)
410 goto done;
411
412 cache->loc = (clidr & 0x7000000) >> 24;
413 LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc);
414
415 /* retrieve selected cache for later restore
416 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
417 retval = dpm->instr_read_data_r0(dpm,
418 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
419 &csselr);
420 if (retval != ERROR_OK)
421 goto done;
422
423 /* retrieve all available inner caches */
424 for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) {
425
426 /* isolate cache type at current level */
427 ctype = clidr & 7;
428
429 /* skip reserved values */
430 if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE)
431 continue;
432
433 /* separate d or unified d/i cache at this level ? */
434 if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) {
435 /* retrieve d-cache info */
436 retval = get_cache_info(dpm, cl, 0, &cache_reg);
437 if (retval != ERROR_OK)
438 goto done;
439 cache->arch[cl].d_u_size = decode_cache_reg(cache_reg);
440
441 LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
442 cache->arch[cl].d_u_size.index,
443 cache->arch[cl].d_u_size.index_shift,
444 cache->arch[cl].d_u_size.way,
445 cache->arch[cl].d_u_size.way_shift);
446
447 LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
448 cache->arch[cl].d_u_size.linelen,
449 cache->arch[cl].d_u_size.cachesize,
450 cache->arch[cl].d_u_size.associativity);
451 }
452
453 /* separate i-cache at this level ? */
454 if (ctype & CACHE_LEVEL_HAS_I_CACHE) {
455 /* retrieve i-cache info */
456 retval = get_cache_info(dpm, cl, 1, &cache_reg);
457 if (retval != ERROR_OK)
458 goto done;
459 cache->arch[cl].i_size = decode_cache_reg(cache_reg);
460
461 LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
462 cache->arch[cl].i_size.index,
463 cache->arch[cl].i_size.index_shift,
464 cache->arch[cl].i_size.way,
465 cache->arch[cl].i_size.way_shift);
466
467 LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
468 cache->arch[cl].i_size.linelen,
469 cache->arch[cl].i_size.cachesize,
470 cache->arch[cl].i_size.associativity);
471 }
472
473 cache->arch[cl].ctype = ctype;
474 }
475
476 /* restore selected cache */
477 dpm->instr_write_data_r0(dpm,
478 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
479 csselr);
480
481 if (retval != ERROR_OK)
482 goto done;
483
484 /* if no l2 cache initialize l1 data cache flush function function */
485 if (!armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache) {
486 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
487 armv7a_cache_auto_flush_all_data;
488 }
489
490 armv7a->armv7a_mmu.armv7a_cache.info = 1;
491 done:
492 dpm->finish(dpm);
493 armv7a_read_mpidr(target);
494 return retval;
495
496 }
497
498 static int armv7a_setup_semihosting(struct target *target, int enable)
499 {
500 struct armv7a_common *armv7a = target_to_armv7a(target);
501 uint32_t vcr;
502 int ret;
503
504 ret = mem_ap_read_atomic_u32(armv7a->debug_ap,
505 armv7a->debug_base + CPUDBG_VCR,
506 &vcr);
507 if (ret < 0) {
508 LOG_ERROR("Failed to read VCR register\n");
509 return ret;
510 }
511
512 if (enable)
513 vcr |= DBG_VCR_SVC_MASK;
514 else
515 vcr &= ~DBG_VCR_SVC_MASK;
516
517 ret = mem_ap_write_atomic_u32(armv7a->debug_ap,
518 armv7a->debug_base + CPUDBG_VCR,
519 vcr);
520 if (ret < 0)
521 LOG_ERROR("Failed to write VCR register\n");
522
523 return ret;
524 }
525
526 int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
527 {
528 struct arm *arm = &armv7a->arm;
529 arm->arch_info = armv7a;
530 target->arch_info = &armv7a->arm;
531 arm->setup_semihosting = armv7a_setup_semihosting;
532 /* target is useful in all function arm v4 5 compatible */
533 armv7a->arm.target = target;
534 armv7a->arm.common_magic = ARM_COMMON_MAGIC;
535 armv7a->common_magic = ARMV7_COMMON_MAGIC;
536 armv7a->armv7a_mmu.armv7a_cache.info = -1;
537 armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL;
538 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
539 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = 1;
540 return ERROR_OK;
541 }
542
543 int armv7a_arch_state(struct target *target)
544 {
545 static const char *state[] = {
546 "disabled", "enabled"
547 };
548
549 struct armv7a_common *armv7a = target_to_armv7a(target);
550 struct arm *arm = &armv7a->arm;
551
552 if (armv7a->common_magic != ARMV7_COMMON_MAGIC) {
553 LOG_ERROR("BUG: called for a non-ARMv7A target");
554 return ERROR_COMMAND_SYNTAX_ERROR;
555 }
556
557 arm_arch_state(target);
558
559 if (armv7a->is_armv7r) {
560 LOG_USER("D-Cache: %s, I-Cache: %s",
561 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
562 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
563 } else {
564 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
565 state[armv7a->armv7a_mmu.mmu_enabled],
566 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
567 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
568 }
569
570 if (arm->core_mode == ARM_MODE_ABT)
571 armv7a_show_fault_registers(target);
572
573 return ERROR_OK;
574 }
575
576 static const struct command_registration l2_cache_commands[] = {
577 {
578 .name = "l2x",
579 .handler = handle_cache_l2x,
580 .mode = COMMAND_EXEC,
581 .help = "configure l2x cache",
582 .usage = "[base_addr] [number_of_way]",
583 },
584 COMMAND_REGISTRATION_DONE
585
586 };
587
588 static const struct command_registration l2x_cache_command_handlers[] = {
589 {
590 .name = "cache_config",
591 .mode = COMMAND_EXEC,
592 .help = "cache configuration for a target",
593 .usage = "",
594 .chain = l2_cache_commands,
595 },
596 COMMAND_REGISTRATION_DONE
597 };
598
599 const struct command_registration armv7a_command_handlers[] = {
600 {
601 .chain = l2x_cache_command_handlers,
602 },
603 {
604 .chain = arm7a_cache_command_handlers,
605 },
606 COMMAND_REGISTRATION_DONE
607 };

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)