flash/nor/tcl: fix segfault on write_image misuse
[openocd.git] / src / flash / nor / tms470.c
1 /***************************************************************************
2 * Copyright (C) 2007,2008 by Christopher Kilgour *
3 * techie |_at_| whiterocker |_dot_| com *
4 * *
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. *
9 * *
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. *
14 * *
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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "imp.h"
26
27 /* ----------------------------------------------------------------------
28 * Internal Support, Helpers
29 * ---------------------------------------------------------------------- */
30
31 struct tms470_flash_bank {
32 unsigned ordinal;
33
34 /* device identification register */
35 uint32_t device_ident_reg;
36 uint32_t silicon_version;
37 uint32_t technology_family;
38 uint32_t rom_flash;
39 uint32_t part_number;
40 const char *part_name;
41
42 };
43
44 static const struct flash_sector TMS470R1A256_SECTORS[] = {
45 {0x00000000, 0x00002000, -1, -1},
46 {0x00002000, 0x00002000, -1, -1},
47 {0x00004000, 0x00002000, -1, -1},
48 {0x00006000, 0x00002000, -1, -1},
49 {0x00008000, 0x00008000, -1, -1},
50 {0x00010000, 0x00008000, -1, -1},
51 {0x00018000, 0x00008000, -1, -1},
52 {0x00020000, 0x00008000, -1, -1},
53 {0x00028000, 0x00008000, -1, -1},
54 {0x00030000, 0x00008000, -1, -1},
55 {0x00038000, 0x00002000, -1, -1},
56 {0x0003A000, 0x00002000, -1, -1},
57 {0x0003C000, 0x00002000, -1, -1},
58 {0x0003E000, 0x00002000, -1, -1},
59 };
60
61 #define TMS470R1A256_NUM_SECTORS \
62 ARRAY_SIZE(TMS470R1A256_SECTORS)
63
64 static const struct flash_sector TMS470R1A288_BANK0_SECTORS[] = {
65 {0x00000000, 0x00002000, -1, -1},
66 {0x00002000, 0x00002000, -1, -1},
67 {0x00004000, 0x00002000, -1, -1},
68 {0x00006000, 0x00002000, -1, -1},
69 };
70
71 #define TMS470R1A288_BANK0_NUM_SECTORS \
72 ARRAY_SIZE(TMS470R1A288_BANK0_SECTORS)
73
74 static const struct flash_sector TMS470R1A288_BANK1_SECTORS[] = {
75 {0x00040000, 0x00010000, -1, -1},
76 {0x00050000, 0x00010000, -1, -1},
77 {0x00060000, 0x00010000, -1, -1},
78 {0x00070000, 0x00010000, -1, -1},
79 };
80
81 #define TMS470R1A288_BANK1_NUM_SECTORS \
82 ARRAY_SIZE(TMS470R1A288_BANK1_SECTORS)
83
84 static const struct flash_sector TMS470R1A384_BANK0_SECTORS[] = {
85 {0x00000000, 0x00002000, -1, -1},
86 {0x00002000, 0x00002000, -1, -1},
87 {0x00004000, 0x00004000, -1, -1},
88 {0x00008000, 0x00004000, -1, -1},
89 {0x0000C000, 0x00004000, -1, -1},
90 {0x00010000, 0x00004000, -1, -1},
91 {0x00014000, 0x00004000, -1, -1},
92 {0x00018000, 0x00002000, -1, -1},
93 {0x0001C000, 0x00002000, -1, -1},
94 {0x0001E000, 0x00002000, -1, -1},
95 };
96
97 #define TMS470R1A384_BANK0_NUM_SECTORS \
98 ARRAY_SIZE(TMS470R1A384_BANK0_SECTORS)
99
100 static const struct flash_sector TMS470R1A384_BANK1_SECTORS[] = {
101 {0x00020000, 0x00008000, -1, -1},
102 {0x00028000, 0x00008000, -1, -1},
103 {0x00030000, 0x00008000, -1, -1},
104 {0x00038000, 0x00008000, -1, -1},
105 };
106
107 #define TMS470R1A384_BANK1_NUM_SECTORS \
108 ARRAY_SIZE(TMS470R1A384_BANK1_SECTORS)
109
110 static const struct flash_sector TMS470R1A384_BANK2_SECTORS[] = {
111 {0x00040000, 0x00008000, -1, -1},
112 {0x00048000, 0x00008000, -1, -1},
113 {0x00050000, 0x00008000, -1, -1},
114 {0x00058000, 0x00008000, -1, -1},
115 };
116
117 #define TMS470R1A384_BANK2_NUM_SECTORS \
118 ARRAY_SIZE(TMS470R1A384_BANK2_SECTORS)
119
120 /* ---------------------------------------------------------------------- */
121
122 static int tms470_read_part_info(struct flash_bank *bank)
123 {
124 struct tms470_flash_bank *tms470_info = bank->driver_priv;
125 struct target *target = bank->target;
126 uint32_t device_ident_reg;
127 uint32_t silicon_version;
128 uint32_t technology_family;
129 uint32_t rom_flash;
130 uint32_t part_number;
131 const char *part_name;
132
133 /* we shall not rely on the caller in this test, this function allocates memory,
134 thus and executing the code more than once may cause memory leak */
135 if (tms470_info->device_ident_reg)
136 return ERROR_OK;
137
138 /* read and parse the device identification register */
139 target_read_u32(target, 0xFFFFFFF0, &device_ident_reg);
140
141 LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg);
142
143 if ((device_ident_reg & 7) == 0) {
144 LOG_WARNING("Cannot identify target as a TMS470 family.");
145 return ERROR_FLASH_OPERATION_FAILED;
146 }
147
148 silicon_version = (device_ident_reg >> 12) & 0xF;
149 technology_family = (device_ident_reg >> 11) & 1;
150 rom_flash = (device_ident_reg >> 10) & 1;
151 part_number = (device_ident_reg >> 3) & 0x7f;
152
153 if (bank->sectors) {
154 free(bank->sectors);
155 bank->sectors = NULL;
156 }
157
158 /*
159 * If the part number is known, determine if the flash bank is valid
160 * based on the base address being within the known flash bank
161 * ranges. Then fixup/complete the remaining fields of the flash
162 * bank structure.
163 */
164 switch (part_number) {
165 case 0x0a:
166 part_name = "TMS470R1A256";
167
168 if (bank->base >= 0x00040000) {
169 LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".",
170 part_name,
171 bank->base);
172 return ERROR_FLASH_OPERATION_FAILED;
173 }
174 tms470_info->ordinal = 0;
175 bank->base = 0x00000000;
176 bank->size = 256 * 1024;
177 bank->num_sectors = TMS470R1A256_NUM_SECTORS;
178 bank->sectors = malloc(sizeof(TMS470R1A256_SECTORS));
179 if (!bank->sectors)
180 return ERROR_FLASH_OPERATION_FAILED;
181 (void)memcpy(bank->sectors, TMS470R1A256_SECTORS, sizeof(TMS470R1A256_SECTORS));
182 break;
183
184 case 0x2b:
185 part_name = "TMS470R1A288";
186
187 if (bank->base < 0x00008000) {
188 tms470_info->ordinal = 0;
189 bank->base = 0x00000000;
190 bank->size = 32 * 1024;
191 bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS;
192 bank->sectors = malloc(sizeof(TMS470R1A288_BANK0_SECTORS));
193 if (!bank->sectors)
194 return ERROR_FLASH_OPERATION_FAILED;
195 (void)memcpy(bank->sectors, TMS470R1A288_BANK0_SECTORS,
196 sizeof(TMS470R1A288_BANK0_SECTORS));
197 } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) {
198 tms470_info->ordinal = 1;
199 bank->base = 0x00040000;
200 bank->size = 256 * 1024;
201 bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS;
202 bank->sectors = malloc(sizeof(TMS470R1A288_BANK1_SECTORS));
203 if (!bank->sectors)
204 return ERROR_FLASH_OPERATION_FAILED;
205 (void)memcpy(bank->sectors, TMS470R1A288_BANK1_SECTORS,
206 sizeof(TMS470R1A288_BANK1_SECTORS));
207 } else {
208 LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".",
209 part_name, bank->base);
210 return ERROR_FLASH_OPERATION_FAILED;
211 }
212 break;
213
214 case 0x2d:
215 part_name = "TMS470R1A384";
216
217 if (bank->base < 0x00020000) {
218 tms470_info->ordinal = 0;
219 bank->base = 0x00000000;
220 bank->size = 128 * 1024;
221 bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS;
222 bank->sectors = malloc(sizeof(TMS470R1A384_BANK0_SECTORS));
223 if (!bank->sectors)
224 return ERROR_FLASH_OPERATION_FAILED;
225 (void)memcpy(bank->sectors, TMS470R1A384_BANK0_SECTORS,
226 sizeof(TMS470R1A384_BANK0_SECTORS));
227 } else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000)) {
228 tms470_info->ordinal = 1;
229 bank->base = 0x00020000;
230 bank->size = 128 * 1024;
231 bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS;
232 bank->sectors = malloc(sizeof(TMS470R1A384_BANK1_SECTORS));
233 if (!bank->sectors)
234 return ERROR_FLASH_OPERATION_FAILED;
235 (void)memcpy(bank->sectors, TMS470R1A384_BANK1_SECTORS,
236 sizeof(TMS470R1A384_BANK1_SECTORS));
237 } else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000)) {
238 tms470_info->ordinal = 2;
239 bank->base = 0x00040000;
240 bank->size = 128 * 1024;
241 bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS;
242 bank->sectors = malloc(sizeof(TMS470R1A384_BANK2_SECTORS));
243 if (!bank->sectors)
244 return ERROR_FLASH_OPERATION_FAILED;
245 (void)memcpy(bank->sectors, TMS470R1A384_BANK2_SECTORS,
246 sizeof(TMS470R1A384_BANK2_SECTORS));
247 } else {
248 LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".",
249 part_name, bank->base);
250 return ERROR_FLASH_OPERATION_FAILED;
251 }
252 break;
253
254 default:
255 LOG_WARNING("Could not identify part 0x%02x as a member of the TMS470 family.",
256 (unsigned)part_number);
257 return ERROR_FLASH_OPERATION_FAILED;
258 }
259
260 /* turn off memory selects */
261 target_write_u32(target, 0xFFFFFFE4, 0x00000000);
262 target_write_u32(target, 0xFFFFFFE0, 0x00000000);
263
264 bank->chip_width = 32;
265 bank->bus_width = 32;
266
267 LOG_INFO("Identified %s, ver=%d, core=%s, nvmem=%s.",
268 part_name,
269 (int)(silicon_version),
270 (technology_family ? "1.8v" : "3.3v"),
271 (rom_flash ? "rom" : "flash"));
272
273 tms470_info->device_ident_reg = device_ident_reg;
274 tms470_info->silicon_version = silicon_version;
275 tms470_info->technology_family = technology_family;
276 tms470_info->rom_flash = rom_flash;
277 tms470_info->part_number = part_number;
278 tms470_info->part_name = part_name;
279
280 /*
281 * Disable reset on address access violation.
282 */
283 target_write_u32(target, 0xFFFFFFE0, 0x00004007);
284
285 return ERROR_OK;
286 }
287
288 /* ---------------------------------------------------------------------- */
289
290 static uint32_t keysSet;
291 static uint32_t flashKeys[4];
292
293 COMMAND_HANDLER(tms470_handle_flash_keyset_command)
294 {
295 if (CMD_ARGC > 4)
296 return ERROR_COMMAND_SYNTAX_ERROR;
297 else if (CMD_ARGC == 4) {
298 int i;
299
300 for (i = 0; i < 4; i++) {
301 int start = (0 == strncmp(CMD_ARGV[i], "0x", 2)) ? 2 : 0;
302
303 if (1 != sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flashKeys[i])) {
304 command_print(CMD_CTX, "could not process flash key %s",
305 CMD_ARGV[i]);
306 LOG_ERROR("could not process flash key %s", CMD_ARGV[i]);
307 return ERROR_COMMAND_SYNTAX_ERROR;
308 }
309 }
310
311 keysSet = 1;
312 } else if (CMD_ARGC != 0) {
313 command_print(CMD_CTX, "tms470 flash_keyset <key0> <key1> <key2> <key3>");
314 return ERROR_COMMAND_SYNTAX_ERROR;
315 }
316
317 if (keysSet) {
318 command_print(CMD_CTX,
319 "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "",
320 flashKeys[0],
321 flashKeys[1],
322 flashKeys[2],
323 flashKeys[3]);
324 } else
325 command_print(CMD_CTX, "flash keys not set");
326
327 return ERROR_OK;
328 }
329
330 static const uint32_t FLASH_KEYS_ALL_ONES[] = { 0xFFFFFFFF, 0xFFFFFFFF,
331 0xFFFFFFFF, 0xFFFFFFFF,};
332
333 static const uint32_t FLASH_KEYS_ALL_ZEROS[] = { 0x00000000, 0x00000000,
334 0x00000000, 0x00000000,};
335
336 static const uint32_t FLASH_KEYS_MIX1[] = { 0xf0fff0ff, 0xf0fff0ff,
337 0xf0fff0ff, 0xf0fff0ff};
338
339 static const uint32_t FLASH_KEYS_MIX2[] = { 0x0000ffff, 0x0000ffff,
340 0x0000ffff, 0x0000ffff};
341
342 /* ---------------------------------------------------------------------- */
343
344 static int oscMHz = 12;
345
346 COMMAND_HANDLER(tms470_handle_osc_megahertz_command)
347 {
348 if (CMD_ARGC > 1)
349 return ERROR_COMMAND_SYNTAX_ERROR;
350 else if (CMD_ARGC == 1)
351 sscanf(CMD_ARGV[0], "%d", &oscMHz);
352
353 if (oscMHz <= 0) {
354 LOG_ERROR("osc_megahertz must be positive and non-zero!");
355 command_print(CMD_CTX, "osc_megahertz must be positive and non-zero!");
356 oscMHz = 12;
357 return ERROR_COMMAND_SYNTAX_ERROR;
358 }
359
360 command_print(CMD_CTX, "osc_megahertz=%d", oscMHz);
361
362 return ERROR_OK;
363 }
364
365 /* ---------------------------------------------------------------------- */
366
367 static int plldis;
368
369 COMMAND_HANDLER(tms470_handle_plldis_command)
370 {
371 if (CMD_ARGC > 1)
372 return ERROR_COMMAND_SYNTAX_ERROR;
373 else if (CMD_ARGC == 1) {
374 sscanf(CMD_ARGV[0], "%d", &plldis);
375 plldis = plldis ? 1 : 0;
376 }
377
378 command_print(CMD_CTX, "plldis=%d", plldis);
379
380 return ERROR_OK;
381 }
382
383 /* ---------------------------------------------------------------------- */
384
385 static int tms470_check_flash_unlocked(struct target *target)
386 {
387 uint32_t fmbbusy;
388
389 target_read_u32(target, 0xFFE89C08, &fmbbusy);
390 LOG_INFO("tms470 fmbbusy = 0x%08" PRIx32 " -> %s",
391 fmbbusy,
392 fmbbusy & 0x8000 ? "unlocked" : "LOCKED");
393 return fmbbusy & 0x8000 ? ERROR_OK : ERROR_FLASH_OPERATION_FAILED;
394 }
395
396 /* ---------------------------------------------------------------------- */
397
398 static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set)
399 {
400 uint32_t glbctrl, fmmstat;
401 int retval = ERROR_FLASH_OPERATION_FAILED;
402
403 /* set GLBCTRL.4 */
404 target_read_u32(target, 0xFFFFFFDC, &glbctrl);
405 target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
406
407 /* only perform the key match when 3VSTAT is clear */
408 target_read_u32(target, 0xFFE8BC0C, &fmmstat);
409 if (!(fmmstat & 0x08)) {
410 unsigned i;
411 uint32_t fmbptr, fmbac2, orig_fmregopt;
412
413 target_write_u32(target, 0xFFE8BC04, fmmstat & ~0x07);
414
415 /* wait for pump ready */
416 do {
417 target_read_u32(target, 0xFFE8A814, &fmbptr);
418 alive_sleep(1);
419 } while (!(fmbptr & 0x0200));
420
421 /* force max wait states */
422 target_read_u32(target, 0xFFE88004, &fmbac2);
423 target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
424
425 /* save current access mode, force normal read mode */
426 target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
427 target_write_u32(target, 0xFFE89C00, 0x00);
428
429 for (i = 0; i < 4; i++) {
430 uint32_t tmp;
431
432 /* There is no point displaying the value of tmp, it is
433 * filtered by the chip. The purpose of this read is to
434 * prime the unlocking logic rather than read out the value.
435 */
436 target_read_u32(target, 0x00001FF0 + 4 * i, &tmp);
437
438 LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]);
439 target_write_u32(target, 0xFFE89C0C, key_set[i]);
440 }
441
442 if (ERROR_OK == tms470_check_flash_unlocked(target)) {
443 /*
444 * There seems to be a side-effect of reading the FMPKEY
445 * register in that it re-enables the protection. So we
446 * re-enable it.
447 */
448 for (i = 0; i < 4; i++) {
449 uint32_t tmp;
450
451 target_read_u32(target, 0x00001FF0 + 4 * i, &tmp);
452 target_write_u32(target, 0xFFE89C0C, key_set[i]);
453 }
454 retval = ERROR_OK;
455 }
456
457 /* restore settings */
458 target_write_u32(target, 0xFFE89C00, orig_fmregopt);
459 target_write_u32(target, 0xFFE88004, fmbac2);
460 }
461
462 /* clear config bit */
463 target_write_u32(target, 0xFFFFFFDC, glbctrl);
464
465 return retval;
466 }
467
468 /* ---------------------------------------------------------------------- */
469
470 static int tms470_unlock_flash(struct flash_bank *bank)
471 {
472 struct target *target = bank->target;
473 const uint32_t *p_key_sets[5];
474 unsigned i, key_set_count;
475
476 if (keysSet) {
477 key_set_count = 5;
478 p_key_sets[0] = flashKeys;
479 p_key_sets[1] = FLASH_KEYS_ALL_ONES;
480 p_key_sets[2] = FLASH_KEYS_ALL_ZEROS;
481 p_key_sets[3] = FLASH_KEYS_MIX1;
482 p_key_sets[4] = FLASH_KEYS_MIX2;
483 } else {
484 key_set_count = 4;
485 p_key_sets[0] = FLASH_KEYS_ALL_ONES;
486 p_key_sets[1] = FLASH_KEYS_ALL_ZEROS;
487 p_key_sets[2] = FLASH_KEYS_MIX1;
488 p_key_sets[3] = FLASH_KEYS_MIX2;
489 }
490
491 for (i = 0; i < key_set_count; i++) {
492 if (tms470_try_flash_keys(target, p_key_sets[i]) == ERROR_OK) {
493 LOG_INFO("tms470 flash is unlocked");
494 return ERROR_OK;
495 }
496 }
497
498 LOG_WARNING("tms470 could not unlock flash memory protection level 2");
499 return ERROR_FLASH_OPERATION_FAILED;
500 }
501
502 /* ---------------------------------------------------------------------- */
503
504 static int tms470_flash_initialize_internal_state_machine(struct flash_bank *bank)
505 {
506 uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk;
507 struct target *target = bank->target;
508 struct tms470_flash_bank *tms470_info = bank->driver_priv;
509 int result = ERROR_OK;
510
511 /*
512 * Select the desired bank to be programmed by writing BANK[2:0] of
513 * FMMAC2.
514 */
515 target_read_u32(target, 0xFFE8BC04, &fmmac2);
516 fmmac2 &= ~0x0007;
517 fmmac2 |= (tms470_info->ordinal & 7);
518 target_write_u32(target, 0xFFE8BC04, fmmac2);
519 LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2);
520
521 /*
522 * Disable level 1 sector protection by setting bit 15 of FMMAC1.
523 */
524 target_read_u32(target, 0xFFE8BC00, &fmmac1);
525 fmmac1 |= 0x8000;
526 target_write_u32(target, 0xFFE8BC00, fmmac1);
527 LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1);
528
529 /*
530 * FMTCREG = 0x2fc0;
531 */
532 target_write_u32(target, 0xFFE8BC10, 0x2fc0);
533 LOG_DEBUG("set fmtcreg = 0x2fc0");
534
535 /*
536 * MAXPP = 50
537 */
538 target_write_u32(target, 0xFFE8A07C, 50);
539 LOG_DEBUG("set fmmaxpp = 50");
540
541 /*
542 * MAXCP = 0xf000 + 2000
543 */
544 target_write_u32(target, 0xFFE8A084, 0xf000 + 2000);
545 LOG_DEBUG("set fmmaxcp = 0x%04x", 0xf000 + 2000);
546
547 /*
548 * configure VHV
549 */
550 target_read_u32(target, 0xFFE8A080, &fmmaxep);
551 if (fmmaxep == 0xf000) {
552 fmmaxep = 0xf000 + 4095;
553 target_write_u32(target, 0xFFE8A80C, 0x9964);
554 LOG_DEBUG("set fmptr3 = 0x9964");
555 } else {
556 fmmaxep = 0xa000 + 4095;
557 target_write_u32(target, 0xFFE8A80C, 0x9b64);
558 LOG_DEBUG("set fmptr3 = 0x9b64");
559 }
560 target_write_u32(target, 0xFFE8A080, fmmaxep);
561 LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep);
562
563 /*
564 * FMPTR4 = 0xa000
565 */
566 target_write_u32(target, 0xFFE8A810, 0xa000);
567 LOG_DEBUG("set fmptr4 = 0xa000");
568
569 /*
570 * FMPESETUP, delay parameter selected based on clock frequency.
571 *
572 * According to the TI App Note SPNU257 and flashing code, delay is
573 * int((sysclk(MHz) + 1) / 2), with a minimum of 5. The system
574 * clock is usually derived from the ZPLL module, and selected by
575 * the plldis global.
576 */
577 target_read_u32(target, 0xFFFFFFDC, &glbctrl);
578 sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * oscMHz / (1 + (glbctrl & 7));
579 delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5;
580 target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8));
581 LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8));
582
583 /*
584 * FMPVEVACCESS, based on delay.
585 */
586 k = delay | (delay << 8);
587 target_write_u32(target, 0xFFE8A05C, k);
588 LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k);
589
590 /*
591 * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay.
592 */
593 k <<= 1;
594 target_write_u32(target, 0xFFE8A034, k);
595 LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k);
596 target_write_u32(target, 0xFFE8A040, k);
597 LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k);
598 target_write_u32(target, 0xFFE8A024, k);
599 LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k);
600
601 /*
602 * FMCVACCESS, based on delay.
603 */
604 k = delay * 16;
605 target_write_u32(target, 0xFFE8A060, k);
606 LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k);
607
608 /*
609 * FMCSETUP, based on delay.
610 */
611 k = 0x3000 | delay * 20;
612 target_write_u32(target, 0xFFE8A020, k);
613 LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k);
614
615 /*
616 * FMEHOLD, based on delay.
617 */
618 k = (delay * 20) << 2;
619 target_write_u32(target, 0xFFE8A038, k);
620 LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k);
621
622 /*
623 * PWIDTH, CWIDTH, EWIDTH, based on delay.
624 */
625 target_write_u32(target, 0xFFE8A050, delay * 8);
626 LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8);
627 target_write_u32(target, 0xFFE8A058, delay * 1000);
628 LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000);
629 target_write_u32(target, 0xFFE8A054, delay * 5400);
630 LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400);
631
632 return result;
633 }
634
635 /* ---------------------------------------------------------------------- */
636
637 static int tms470_flash_status(struct flash_bank *bank)
638 {
639 struct target *target = bank->target;
640 int result = ERROR_OK;
641 uint32_t fmmstat;
642
643 target_read_u32(target, 0xFFE8BC0C, &fmmstat);
644 LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat);
645
646 if (fmmstat & 0x0080) {
647 LOG_WARNING("tms470 flash command: erase still active after busy clear.");
648 result = ERROR_FLASH_OPERATION_FAILED;
649 }
650
651 if (fmmstat & 0x0040) {
652 LOG_WARNING("tms470 flash command: program still active after busy clear.");
653 result = ERROR_FLASH_OPERATION_FAILED;
654 }
655
656 if (fmmstat & 0x0020) {
657 LOG_WARNING("tms470 flash command: invalid data command.");
658 result = ERROR_FLASH_OPERATION_FAILED;
659 }
660
661 if (fmmstat & 0x0010) {
662 LOG_WARNING("tms470 flash command: program, erase or validate sector failed.");
663 result = ERROR_FLASH_OPERATION_FAILED;
664 }
665
666 if (fmmstat & 0x0008) {
667 LOG_WARNING("tms470 flash command: voltage instability detected.");
668 result = ERROR_FLASH_OPERATION_FAILED;
669 }
670
671 if (fmmstat & 0x0006) {
672 LOG_WARNING("tms470 flash command: command suspend detected.");
673 result = ERROR_FLASH_OPERATION_FAILED;
674 }
675
676 if (fmmstat & 0x0001) {
677 LOG_WARNING("tms470 flash command: sector was locked.");
678 result = ERROR_FLASH_OPERATION_FAILED;
679 }
680
681 return result;
682 }
683
684 /* ---------------------------------------------------------------------- */
685
686 static int tms470_erase_sector(struct flash_bank *bank, int sector)
687 {
688 uint32_t glbctrl, orig_fmregopt, fmbsea, fmbseb, fmmstat;
689 struct target *target = bank->target;
690 uint32_t flashAddr = bank->base + bank->sectors[sector].offset;
691 int result = ERROR_OK;
692
693 /*
694 * Set the bit GLBCTRL4 of the GLBCTRL register (in the System
695 * module) to enable writing to the flash registers }.
696 */
697 target_read_u32(target, 0xFFFFFFDC, &glbctrl);
698 target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
699 LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10);
700
701 /* Force normal read mode. */
702 target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
703 target_write_u32(target, 0xFFE89C00, 0);
704 LOG_DEBUG("set fmregopt = 0x%08x", 0);
705
706 (void)tms470_flash_initialize_internal_state_machine(bank);
707
708 /*
709 * Select one or more bits in FMBSEA or FMBSEB to disable Level 1
710 * protection for the particular sector to be erased/written.
711 */
712 if (sector < 16) {
713 target_read_u32(target, 0xFFE88008, &fmbsea);
714 target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector));
715 LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector));
716 } else {
717 target_read_u32(target, 0xFFE8800C, &fmbseb);
718 target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16)));
719 LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16)));
720 }
721 bank->sectors[sector].is_protected = 0;
722
723 /*
724 * clear status regiser, sent erase command, kickoff erase
725 */
726 target_write_u16(target, flashAddr, 0x0040);
727 LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flashAddr);
728 target_write_u16(target, flashAddr, 0x0020);
729 LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flashAddr);
730 target_write_u16(target, flashAddr, 0xffff);
731 LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flashAddr);
732
733 /*
734 * Monitor FMMSTAT, busy until clear, then check and other flags for
735 * ultimate result of the operation.
736 */
737 do {
738 target_read_u32(target, 0xFFE8BC0C, &fmmstat);
739 if (fmmstat & 0x0100)
740 alive_sleep(1);
741 } while (fmmstat & 0x0100);
742
743 result = tms470_flash_status(bank);
744
745 if (sector < 16) {
746 target_write_u32(target, 0xFFE88008, fmbsea);
747 LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea);
748 bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1;
749 } else {
750 target_write_u32(target, 0xFFE8800C, fmbseb);
751 LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb);
752 bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1;
753 }
754 target_write_u32(target, 0xFFE89C00, orig_fmregopt);
755 LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt);
756 target_write_u32(target, 0xFFFFFFDC, glbctrl);
757 LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl);
758
759 if (result == ERROR_OK)
760 bank->sectors[sector].is_erased = 1;
761
762 return result;
763 }
764
765 /*----------------------------------------------------------------------
766 * Implementation of Flash Driver Interfaces
767 *---------------------------------------------------------------------- */
768
769 static const struct command_registration tms470_any_command_handlers[] = {
770 {
771 .name = "flash_keyset",
772 .usage = "<key0> <key1> <key2> <key3>",
773 .handler = tms470_handle_flash_keyset_command,
774 .mode = COMMAND_ANY,
775 .help = "tms470 flash_keyset <key0> <key1> <key2> <key3>",
776 },
777 {
778 .name = "osc_megahertz",
779 .usage = "<MHz>",
780 .handler = tms470_handle_osc_megahertz_command,
781 .mode = COMMAND_ANY,
782 .help = "tms470 osc_megahertz <MHz>",
783 },
784 {
785 .name = "plldis",
786 .usage = "<0 | 1>",
787 .handler = tms470_handle_plldis_command,
788 .mode = COMMAND_ANY,
789 .help = "tms470 plldis <0/1>",
790 },
791 COMMAND_REGISTRATION_DONE
792 };
793 static const struct command_registration tms470_command_handlers[] = {
794 {
795 .name = "tms470",
796 .mode = COMMAND_ANY,
797 .help = "TI tms470 flash command group",
798 .usage = "",
799 .chain = tms470_any_command_handlers,
800 },
801 COMMAND_REGISTRATION_DONE
802 };
803
804 /* ---------------------------------------------------------------------- */
805
806 static int tms470_erase(struct flash_bank *bank, int first, int last)
807 {
808 struct tms470_flash_bank *tms470_info = bank->driver_priv;
809 int sector, result = ERROR_OK;
810
811 if (bank->target->state != TARGET_HALTED) {
812 LOG_ERROR("Target not halted");
813 return ERROR_TARGET_NOT_HALTED;
814 }
815
816 tms470_read_part_info(bank);
817
818 if ((first < 0) || (first >= bank->num_sectors) || (last < 0) ||
819 (last >= bank->num_sectors) || (first > last)) {
820 LOG_ERROR("Sector range %d to %d invalid.", first, last);
821 return ERROR_FLASH_SECTOR_INVALID;
822 }
823
824 result = tms470_unlock_flash(bank);
825 if (result != ERROR_OK)
826 return result;
827
828 for (sector = first; sector <= last; sector++) {
829 LOG_INFO("Erasing tms470 bank %d sector %d...", tms470_info->ordinal, sector);
830
831 result = tms470_erase_sector(bank, sector);
832
833 if (result != ERROR_OK) {
834 LOG_ERROR("tms470 could not erase flash sector.");
835 break;
836 } else
837 LOG_INFO("sector erased successfully.");
838 }
839
840 return result;
841 }
842
843 /* ---------------------------------------------------------------------- */
844
845 static int tms470_protect(struct flash_bank *bank, int set, int first, int last)
846 {
847 struct tms470_flash_bank *tms470_info = bank->driver_priv;
848 struct target *target = bank->target;
849 uint32_t fmmac2, fmbsea, fmbseb;
850 int sector;
851
852 if (target->state != TARGET_HALTED) {
853 LOG_ERROR("Target not halted");
854 return ERROR_TARGET_NOT_HALTED;
855 }
856
857 tms470_read_part_info(bank);
858
859 if ((first < 0) || (first >= bank->num_sectors) || (last < 0) ||
860 (last >= bank->num_sectors) || (first > last)) {
861 LOG_ERROR("Sector range %d to %d invalid.", first, last);
862 return ERROR_FLASH_SECTOR_INVALID;
863 }
864
865 /* enable the appropriate bank */
866 target_read_u32(target, 0xFFE8BC04, &fmmac2);
867 target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
868
869 /* get the original sector proection flags for this bank */
870 target_read_u32(target, 0xFFE88008, &fmbsea);
871 target_read_u32(target, 0xFFE8800C, &fmbseb);
872
873 for (sector = 0; sector < bank->num_sectors; sector++) {
874 if (sector < 16) {
875 fmbsea = set ? fmbsea & ~(1 << sector) : fmbsea | (1 << sector);
876 bank->sectors[sector].is_protected = set ? 1 : 0;
877 } else {
878 fmbseb = set ? fmbseb &
879 ~(1 << (sector - 16)) : fmbseb | (1 << (sector - 16));
880 bank->sectors[sector].is_protected = set ? 1 : 0;
881 }
882 }
883
884 /* update the protection bits */
885 target_write_u32(target, 0xFFE88008, fmbsea);
886 target_write_u32(target, 0xFFE8800C, fmbseb);
887
888 return ERROR_OK;
889 }
890
891 /* ---------------------------------------------------------------------- */
892
893 static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
894 {
895 struct target *target = bank->target;
896 uint32_t glbctrl, fmbac2, orig_fmregopt, fmbsea, fmbseb, fmmaxpp, fmmstat;
897 int result = ERROR_OK;
898 uint32_t i;
899
900 if (target->state != TARGET_HALTED) {
901 LOG_ERROR("Target not halted");
902 return ERROR_TARGET_NOT_HALTED;
903 }
904
905 tms470_read_part_info(bank);
906
907 LOG_INFO("Writing %" PRId32 " bytes starting at 0x%08" PRIx32 "", count, bank->base +
908 offset);
909
910 /* set GLBCTRL.4 */
911 target_read_u32(target, 0xFFFFFFDC, &glbctrl);
912 target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
913
914 (void)tms470_flash_initialize_internal_state_machine(bank);
915
916 /* force max wait states */
917 target_read_u32(target, 0xFFE88004, &fmbac2);
918 target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
919
920 /* save current access mode, force normal read mode */
921 target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
922 target_write_u32(target, 0xFFE89C00, 0x00);
923
924 /*
925 * Disable Level 1 protection for all sectors to be erased/written.
926 */
927 target_read_u32(target, 0xFFE88008, &fmbsea);
928 target_write_u32(target, 0xFFE88008, 0xffff);
929 target_read_u32(target, 0xFFE8800C, &fmbseb);
930 target_write_u32(target, 0xFFE8800C, 0xffff);
931
932 /* read MAXPP */
933 target_read_u32(target, 0xFFE8A07C, &fmmaxpp);
934
935 for (i = 0; i < count; i += 2) {
936 uint32_t addr = bank->base + offset + i;
937 uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1];
938
939 if (word != 0xffff) {
940 LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr);
941
942 /* clear status register */
943 target_write_u16(target, addr, 0x0040);
944 /* program flash command */
945 target_write_u16(target, addr, 0x0010);
946 /* burn the 16-bit word (big-endian) */
947 target_write_u16(target, addr, word);
948
949 /*
950 * Monitor FMMSTAT, busy until clear, then check and other flags
951 * for ultimate result of the operation.
952 */
953 do {
954 target_read_u32(target, 0xFFE8BC0C, &fmmstat);
955 if (fmmstat & 0x0100)
956 alive_sleep(1);
957 } while (fmmstat & 0x0100);
958
959 if (fmmstat & 0x3ff) {
960 LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat);
961 LOG_ERROR(
962 "Could not program word 0x%04x at address 0x%08" PRIx32 ".",
963 word,
964 addr);
965 result = ERROR_FLASH_OPERATION_FAILED;
966 break;
967 }
968 } else
969 LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr);
970 }
971
972 /* restore */
973 target_write_u32(target, 0xFFE88008, fmbsea);
974 target_write_u32(target, 0xFFE8800C, fmbseb);
975 target_write_u32(target, 0xFFE88004, fmbac2);
976 target_write_u32(target, 0xFFE89C00, orig_fmregopt);
977 target_write_u32(target, 0xFFFFFFDC, glbctrl);
978
979 return result;
980 }
981
982 /* ---------------------------------------------------------------------- */
983
984 static int tms470_probe(struct flash_bank *bank)
985 {
986 if (bank->target->state != TARGET_HALTED) {
987 LOG_WARNING("Cannot communicate... target not halted.");
988 return ERROR_TARGET_NOT_HALTED;
989 }
990
991 return tms470_read_part_info(bank);
992 }
993
994 static int tms470_auto_probe(struct flash_bank *bank)
995 {
996 struct tms470_flash_bank *tms470_info = bank->driver_priv;
997
998 if (tms470_info->device_ident_reg)
999 return ERROR_OK;
1000 return tms470_probe(bank);
1001 }
1002
1003 /* ---------------------------------------------------------------------- */
1004
1005 static int tms470_erase_check(struct flash_bank *bank)
1006 {
1007 struct target *target = bank->target;
1008 struct tms470_flash_bank *tms470_info = bank->driver_priv;
1009 int sector, result = ERROR_OK;
1010 uint32_t fmmac2, fmbac2, glbctrl, orig_fmregopt;
1011 static uint8_t buffer[64 * 1024];
1012
1013 if (target->state != TARGET_HALTED) {
1014 LOG_ERROR("Target not halted");
1015 return ERROR_TARGET_NOT_HALTED;
1016 }
1017
1018 if (!tms470_info->device_ident_reg)
1019 tms470_read_part_info(bank);
1020
1021 /* set GLBCTRL.4 */
1022 target_read_u32(target, 0xFFFFFFDC, &glbctrl);
1023 target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10);
1024
1025 /* save current access mode, force normal read mode */
1026 target_read_u32(target, 0xFFE89C00, &orig_fmregopt);
1027 target_write_u32(target, 0xFFE89C00, 0x00);
1028
1029 /* enable the appropriate bank */
1030 target_read_u32(target, 0xFFE8BC04, &fmmac2);
1031 target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
1032
1033 /* TCR = 0 */
1034 target_write_u32(target, 0xFFE8BC10, 0x2fc0);
1035
1036 /* clear TEZ in fmbrdy */
1037 target_write_u32(target, 0xFFE88010, 0x0b);
1038
1039 /* save current wait states, force max */
1040 target_read_u32(target, 0xFFE88004, &fmbac2);
1041 target_write_u32(target, 0xFFE88004, fmbac2 | 0xff);
1042
1043 /*
1044 * The TI primitives inspect the flash memory by reading one 32-bit
1045 * word at a time. Here we read an entire sector and inspect it in
1046 * an attempt to reduce the JTAG overhead.
1047 */
1048 for (sector = 0; sector < bank->num_sectors; sector++) {
1049 if (bank->sectors[sector].is_erased != 1) {
1050 uint32_t i, addr = bank->base + bank->sectors[sector].offset;
1051
1052 LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
1053
1054 target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
1055
1056 bank->sectors[sector].is_erased = 1;
1057 for (i = 0; i < bank->sectors[sector].size; i++) {
1058 if (buffer[i] != 0xff) {
1059 LOG_WARNING("tms470 bank %d, sector %d, not erased.",
1060 tms470_info->ordinal,
1061 sector);
1062 LOG_WARNING(
1063 "at location 0x%08" PRIx32 ": flash data is 0x%02x.",
1064 addr + i,
1065 buffer[i]);
1066
1067 bank->sectors[sector].is_erased = 0;
1068 break;
1069 }
1070 }
1071 }
1072 if (bank->sectors[sector].is_erased != 1) {
1073 result = ERROR_FLASH_SECTOR_NOT_ERASED;
1074 break;
1075 } else
1076 LOG_INFO("sector erased");
1077 }
1078
1079 /* reset TEZ, wait states, read mode, GLBCTRL.4 */
1080 target_write_u32(target, 0xFFE88010, 0x0f);
1081 target_write_u32(target, 0xFFE88004, fmbac2);
1082 target_write_u32(target, 0xFFE89C00, orig_fmregopt);
1083 target_write_u32(target, 0xFFFFFFDC, glbctrl);
1084
1085 return result;
1086 }
1087
1088 /* ---------------------------------------------------------------------- */
1089
1090 static int tms470_protect_check(struct flash_bank *bank)
1091 {
1092 struct target *target = bank->target;
1093 struct tms470_flash_bank *tms470_info = bank->driver_priv;
1094 int sector, result = ERROR_OK;
1095 uint32_t fmmac2, fmbsea, fmbseb;
1096
1097 if (target->state != TARGET_HALTED) {
1098 LOG_ERROR("Target not halted");
1099 return ERROR_TARGET_NOT_HALTED;
1100 }
1101
1102 if (!tms470_info->device_ident_reg)
1103 tms470_read_part_info(bank);
1104
1105 /* enable the appropriate bank */
1106 target_read_u32(target, 0xFFE8BC04, &fmmac2);
1107 target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal);
1108
1109 target_read_u32(target, 0xFFE88008, &fmbsea);
1110 target_read_u32(target, 0xFFE8800C, &fmbseb);
1111
1112 for (sector = 0; sector < bank->num_sectors; sector++) {
1113 int protected;
1114
1115 if (sector < 16) {
1116 protected = fmbsea & (1 << sector) ? 0 : 1;
1117 bank->sectors[sector].is_protected = protected;
1118 } else {
1119 protected = fmbseb & (1 << (sector - 16)) ? 0 : 1;
1120 bank->sectors[sector].is_protected = protected;
1121 }
1122
1123 LOG_DEBUG("bank %d sector %d is %s",
1124 tms470_info->ordinal,
1125 sector,
1126 protected ? "protected" : "not protected");
1127 }
1128
1129 return result;
1130 }
1131
1132 /* ---------------------------------------------------------------------- */
1133
1134 static int get_tms470_info(struct flash_bank *bank, char *buf, int buf_size)
1135 {
1136 int used = 0;
1137 struct tms470_flash_bank *tms470_info = bank->driver_priv;
1138
1139 if (!tms470_info->device_ident_reg)
1140 tms470_read_part_info(bank);
1141
1142 if (!tms470_info->device_ident_reg) {
1143 (void)snprintf(buf, buf_size, "Cannot identify target as a TMS470\n");
1144 return ERROR_FLASH_OPERATION_FAILED;
1145 }
1146
1147 used =
1148 snprintf(buf, buf_size, "\ntms470 information: Chip is %s\n",
1149 tms470_info->part_name);
1150 buf += used;
1151 buf_size -= used;
1152
1153 snprintf(buf, buf_size, "Flash protection level 2 is %s\n",
1154 tms470_check_flash_unlocked(bank->target) == ERROR_OK ? "disabled" : "enabled");
1155
1156 return ERROR_OK;
1157 }
1158
1159 /* ---------------------------------------------------------------------- */
1160
1161 /*
1162 * flash bank tms470 <base> <size> <chip_width> <bus_width> <target>
1163 * [options...]
1164 */
1165
1166 FLASH_BANK_COMMAND_HANDLER(tms470_flash_bank_command)
1167 {
1168 bank->driver_priv = malloc(sizeof(struct tms470_flash_bank));
1169
1170 if (!bank->driver_priv)
1171 return ERROR_FLASH_OPERATION_FAILED;
1172
1173 (void)memset(bank->driver_priv, 0, sizeof(struct tms470_flash_bank));
1174
1175 return ERROR_OK;
1176 }
1177
1178 struct flash_driver tms470_flash = {
1179 .name = "tms470",
1180 .commands = tms470_command_handlers,
1181 .flash_bank_command = tms470_flash_bank_command,
1182 .erase = tms470_erase,
1183 .protect = tms470_protect,
1184 .write = tms470_write,
1185 .read = default_flash_read,
1186 .probe = tms470_probe,
1187 .auto_probe = tms470_auto_probe,
1188 .erase_check = tms470_erase_check,
1189 .protect_check = tms470_protect_check,
1190 .info = get_tms470_info,
1191 };

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)