1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
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. *
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. *
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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
24 #include "replacements.h"
32 #include "algorithm.h"
33 #include "binarybuffer.h"
40 int cfi_register_commands(struct command_context_s
*cmd_ctx
);
41 int cfi_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
);
42 int cfi_erase(struct flash_bank_s
*bank
, int first
, int last
);
43 int cfi_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
);
44 int cfi_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
);
45 int cfi_probe(struct flash_bank_s
*bank
);
46 int cfi_erase_check(struct flash_bank_s
*bank
);
47 int cfi_protect_check(struct flash_bank_s
*bank
);
48 int cfi_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
);
50 int cfi_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
52 #define CFI_MAX_BUS_WIDTH 4
53 #define CFI_MAX_CHIP_WIDTH 4
55 flash_driver_t cfi_flash
=
58 .register_commands
= cfi_register_commands
,
59 .flash_bank_command
= cfi_flash_bank_command
,
61 .protect
= cfi_protect
,
64 .erase_check
= cfi_erase_check
,
65 .protect_check
= cfi_protect_check
,
69 inline u32
flash_address(flash_bank_t
*bank
, int sector
, u32 offset
)
71 /* while the sector list isn't built, only accesses to sector 0 work */
73 return bank
->base
+ offset
* bank
->bus_width
;
78 ERROR("BUG: sector list not yet built");
81 return bank
->base
+ bank
->sectors
[sector
].offset
+ offset
* bank
->bus_width
;
86 void cfi_command(flash_bank_t
*bank
, u8 cmd
, u8
*cmd_buf
)
88 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
91 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
93 for (i
= bank
->bus_width
; i
> 0; i
--)
95 *cmd_buf
++ = (i
& (bank
->chip_width
- 1)) ? 0x0 : cmd
;
100 for (i
= 1; i
<= bank
->bus_width
; i
++)
102 *cmd_buf
++ = (i
& (bank
->chip_width
- 1)) ? 0x0 : cmd
;
107 /* read unsigned 8-bit value from the bank
108 * flash banks are expected to be made of similar chips
109 * the query result should be the same for all
111 u8
cfi_query_u8(flash_bank_t
*bank
, int sector
, u32 offset
)
113 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
114 target_t
*target
= cfi_info
->target
;
115 u8 data
[CFI_MAX_BUS_WIDTH
];
117 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 1, data
);
119 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
122 return data
[bank
->bus_width
- 1];
125 /* read unsigned 8-bit value from the bank
126 * in case of a bank made of multiple chips,
127 * the individual values are ORed
129 u8
cfi_get_u8(flash_bank_t
*bank
, int sector
, u32 offset
)
131 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
132 target_t
*target
= cfi_info
->target
;
133 u8 data
[CFI_MAX_BUS_WIDTH
];
136 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 1, data
);
138 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
140 for (i
= 0; i
< bank
->bus_width
/ bank
->chip_width
; i
++)
148 for (i
= 0; i
< bank
->bus_width
/ bank
->chip_width
; i
++)
149 value
|= data
[bank
->bus_width
- 1 - i
];
155 u16
cfi_query_u16(flash_bank_t
*bank
, int sector
, u32 offset
)
157 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
158 target_t
*target
= cfi_info
->target
;
159 u8 data
[CFI_MAX_BUS_WIDTH
* 2];
161 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 2, data
);
163 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
164 return data
[0] | data
[bank
->bus_width
] << 8;
166 return data
[bank
->bus_width
- 1] | data
[(2 * bank
->bus_width
) - 1] << 8;
169 u32
cfi_query_u32(flash_bank_t
*bank
, int sector
, u32 offset
)
171 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
172 target_t
*target
= cfi_info
->target
;
173 u8 data
[CFI_MAX_BUS_WIDTH
* 4];
175 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 4, data
);
177 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
178 return data
[0] | data
[bank
->bus_width
] << 8 | data
[bank
->bus_width
* 2] << 16 | data
[bank
->bus_width
* 3] << 24;
180 return data
[bank
->bus_width
- 1] | data
[(2* bank
->bus_width
) - 1] << 8 |
181 data
[(3 * bank
->bus_width
) - 1] << 16 | data
[(4 * bank
->bus_width
) - 1] << 24;
184 void cfi_intel_clear_status_register(flash_bank_t
*bank
)
186 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
187 target_t
*target
= cfi_info
->target
;
190 if (target
->state
!= TARGET_HALTED
)
192 ERROR("BUG: attempted to clear status register while target wasn't halted");
196 cfi_command(bank
, 0x50, command
);
197 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
200 u8
cfi_intel_wait_status_busy(flash_bank_t
*bank
, int timeout
)
204 while ((!((status
= cfi_get_u8(bank
, 0, 0x0)) & 0x80)) && (timeout
-- > 0))
206 DEBUG("status: 0x%x", status
);
210 DEBUG("status: 0x%x", status
);
214 ERROR("status register: 0x%x", status
);
216 ERROR("Block Lock-Bit Detected, Operation Abort");
218 ERROR("Program suspended");
220 ERROR("Low Programming Voltage Detected, Operation Aborted");
222 ERROR("Program Error / Error in Setting Lock-Bit");
224 ERROR("Error in Block Erasure or Clear Lock-Bits");
226 ERROR("Block Erase Suspended");
228 cfi_intel_clear_status_register(bank
);
233 int cfi_read_intel_pri_ext(flash_bank_t
*bank
)
235 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
236 cfi_intel_pri_ext_t
*pri_ext
= malloc(sizeof(cfi_intel_pri_ext_t
));
237 target_t
*target
= cfi_info
->target
;
240 cfi_info
->pri_ext
= pri_ext
;
242 pri_ext
->pri
[0] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0);
243 pri_ext
->pri
[1] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 1);
244 pri_ext
->pri
[2] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 2);
246 if ((pri_ext
->pri
[0] != 'P') || (pri_ext
->pri
[1] != 'R') || (pri_ext
->pri
[2] != 'I'))
248 cfi_command(bank
, 0xf0, command
);
249 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
250 cfi_command(bank
, 0xff, command
);
251 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
252 return ERROR_FLASH_BANK_INVALID
;
255 pri_ext
->major_version
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 3);
256 pri_ext
->minor_version
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 4);
258 DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext
->pri
[0], pri_ext
->pri
[1], pri_ext
->pri
[2], pri_ext
->major_version
, pri_ext
->minor_version
);
260 pri_ext
->feature_support
= cfi_query_u32(bank
, 0, cfi_info
->pri_addr
+ 5);
261 pri_ext
->suspend_cmd_support
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 9);
262 pri_ext
->blk_status_reg_mask
= cfi_query_u16(bank
, 0, cfi_info
->pri_addr
+ 0xa);
264 DEBUG("feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", pri_ext
->feature_support
, pri_ext
->suspend_cmd_support
, pri_ext
->blk_status_reg_mask
);
266 pri_ext
->vcc_optimal
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xc);
267 pri_ext
->vpp_optimal
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xd);
269 DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
270 (pri_ext
->vcc_optimal
& 0xf0) >> 4, pri_ext
->vcc_optimal
& 0x0f,
271 (pri_ext
->vpp_optimal
& 0xf0) >> 4, pri_ext
->vpp_optimal
& 0x0f);
273 pri_ext
->num_protection_fields
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xe);
274 if (pri_ext
->num_protection_fields
!= 1)
276 WARNING("expected one protection register field, but found %i", pri_ext
->num_protection_fields
);
279 pri_ext
->prot_reg_addr
= cfi_query_u16(bank
, 0, cfi_info
->pri_addr
+ 0xf);
280 pri_ext
->fact_prot_reg_size
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0x11);
281 pri_ext
->user_prot_reg_size
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0x12);
283 DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext
->num_protection_fields
, pri_ext
->prot_reg_addr
, 1 << pri_ext
->fact_prot_reg_size
, 1 << pri_ext
->user_prot_reg_size
);
288 int cfi_intel_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
291 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
292 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
294 printed
= snprintf(buf
, buf_size
, "\nintel primary algorithm extend information:\n");
298 printed
= snprintf(buf
, buf_size
, "pri: '%c%c%c', version: %c.%c\n", pri_ext
->pri
[0], pri_ext
->pri
[1], pri_ext
->pri
[2], pri_ext
->major_version
, pri_ext
->minor_version
);
302 printed
= snprintf(buf
, buf_size
, "feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext
->feature_support
, pri_ext
->suspend_cmd_support
, pri_ext
->blk_status_reg_mask
);
306 printed
= snprintf(buf
, buf_size
, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
307 (pri_ext
->vcc_optimal
& 0xf0) >> 4, pri_ext
->vcc_optimal
& 0x0f,
308 (pri_ext
->vpp_optimal
& 0xf0) >> 4, pri_ext
->vpp_optimal
& 0x0f);
312 printed
= snprintf(buf
, buf_size
, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext
->num_protection_fields
, pri_ext
->prot_reg_addr
, 1 << pri_ext
->fact_prot_reg_size
, 1 << pri_ext
->user_prot_reg_size
);
317 int cfi_register_commands(struct command_context_s
*cmd_ctx
)
319 command_t
*cfi_cmd
= register_command(cmd_ctx
, NULL
, "cfi", NULL
, COMMAND_ANY
, NULL
);
321 register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
322 "print part id of cfi flash bank <num>");
327 /* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#>
329 int cfi_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
)
331 cfi_flash_bank_t
*cfi_info
;
335 WARNING("incomplete flash_bank cfi configuration");
336 return ERROR_FLASH_BANK_INVALID
;
339 if ((strtoul(args
[4], NULL
, 0) > CFI_MAX_CHIP_WIDTH
)
340 || (strtoul(args
[3], NULL
, 0) > CFI_MAX_BUS_WIDTH
))
342 ERROR("chip and bus width have to specified in byte");
343 return ERROR_FLASH_BANK_INVALID
;
346 cfi_info
= malloc(sizeof(cfi_flash_bank_t
));
347 bank
->driver_priv
= cfi_info
;
349 cfi_info
->target
= get_target_by_num(strtoul(args
[5], NULL
, 0));
350 if (!cfi_info
->target
)
352 ERROR("no target '%i' configured", args
[5]);
356 /* bank wasn't probed yet */
357 cfi_info
->qry
[0] = -1;
362 int cfi_intel_erase(struct flash_bank_s
*bank
, int first
, int last
)
364 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
365 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
366 target_t
*target
= cfi_info
->target
;
370 cfi_intel_clear_status_register(bank
);
372 for (i
= first
; i
<= last
; i
++)
374 cfi_command(bank
, 0x20, command
);
375 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
377 cfi_command(bank
, 0xd0, command
);
378 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
380 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->block_erase_timeout_typ
)) == 0x80)
381 bank
->sectors
[i
].is_erased
= 1;
384 cfi_command(bank
, 0xff, command
);
385 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
387 ERROR("couldn't erase block %i of flash bank at base 0x%x", i
, bank
->base
);
388 return ERROR_FLASH_OPERATION_FAILED
;
392 cfi_command(bank
, 0xff, command
);
393 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
398 int cfi_erase(struct flash_bank_s
*bank
, int first
, int last
)
400 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
402 if (cfi_info
->target
->state
!= TARGET_HALTED
)
404 return ERROR_TARGET_NOT_HALTED
;
407 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
409 return ERROR_FLASH_SECTOR_INVALID
;
412 if (cfi_info
->qry
[0] != 'Q')
413 return ERROR_FLASH_BANK_NOT_PROBED
;
415 switch(cfi_info
->pri_id
)
419 return cfi_intel_erase(bank
, first
, last
);
422 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
429 int cfi_intel_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
431 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
432 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
433 target_t
*target
= cfi_info
->target
;
437 if (!(pri_ext
->feature_support
& 0x28))
438 return ERROR_FLASH_OPERATION_FAILED
;
440 cfi_intel_clear_status_register(bank
);
442 for (i
= first
; i
<= last
; i
++)
444 cfi_command(bank
, 0x60, command
);
445 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
448 cfi_command(bank
, 0x01, command
);
449 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
450 bank
->sectors
[i
].is_protected
= 1;
454 cfi_command(bank
, 0xd0, command
);
455 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
456 bank
->sectors
[i
].is_protected
= 0;
459 cfi_intel_wait_status_busy(bank
, 100);
462 /* if the device doesn't support individual block lock bits set/clear,
463 * all blocks have been unlocked in parallel, so we set those that should be protected
465 if ((!set
) && (!(pri_ext
->feature_support
& 0x20)))
467 for (i
= 0; i
< bank
->num_sectors
; i
++)
469 cfi_intel_clear_status_register(bank
);
470 cfi_command(bank
, 0x60, command
);
471 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
472 if (bank
->sectors
[i
].is_protected
== 1)
474 cfi_command(bank
, 0x01, command
);
475 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
478 cfi_intel_wait_status_busy(bank
, 100);
482 cfi_command(bank
, 0xff, command
);
483 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
488 int cfi_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
490 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
492 if (cfi_info
->target
->state
!= TARGET_HALTED
)
494 return ERROR_TARGET_NOT_HALTED
;
497 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
499 return ERROR_FLASH_SECTOR_INVALID
;
502 if (cfi_info
->qry
[0] != 'Q')
503 return ERROR_FLASH_BANK_NOT_PROBED
;
505 switch(cfi_info
->pri_id
)
509 cfi_intel_protect(bank
, set
, first
, last
);
512 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
519 void cfi_add_byte(struct flash_bank_s
*bank
, u8
*word
, u8 byte
)
521 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
522 target_t
*target
= cfi_info
->target
;
526 if (target
->endianness
== TARGET_LITTLE_ENDIAN
)
529 for (i
= 0; i
< bank
->bus_width
- 1; i
++)
530 word
[i
] = word
[i
+ 1];
531 word
[bank
->bus_width
- 1] = byte
;
536 for (i
= bank
->bus_width
- 1; i
> 0; i
--)
537 word
[i
] = word
[i
- 1];
542 int cfi_intel_write_block(struct flash_bank_s
*bank
, u8
*buffer
, u32 address
, u32 count
)
544 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
545 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
546 target_t
*target
= cfi_info
->target
;
547 reg_param_t reg_params
[5];
548 armv4_5_algorithm_t armv4_5_info
;
549 working_area_t
*source
;
550 u32 buffer_size
= 32768;
551 u8 write_command
[CFI_MAX_BUS_WIDTH
];
555 u32 word_32_code
[] = {
556 0xe4904004, /* loop: ldr r4, [r0], #4 */
557 0xe5813000, /* str r3, [r1] */
558 0xe5814000, /* str r4, [r1] */
559 0xe5914000, /* busy ldr r4, [r1] */
560 0xe3140080, /* tst r4, #0x80 */
561 0x0afffffc, /* beq busy */
562 0xe314007f, /* tst r4, #0x7f */
563 0x1a000003, /* bne done */
564 0xe2522001, /* subs r2, r2, #1 */
565 0x0a000001, /* beq done */
566 0xe2811004, /* add r1, r1 #4 */
567 0xeafffff3, /* b loop */
568 0xeafffffe, /* done: b -2 */
571 u32 word_16_code
[] = {
572 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
573 0xe1c130b0, /* strh r3, [r1] */
574 0xe1c140b0, /* strh r4, [r1] */
575 0xe1d140b0, /* busy ldrh r4, [r1] */
576 0xe3140080, /* tst r4, #0x80 */
577 0x0afffffc, /* beq busy */
578 0xe314007f, /* tst r4, #0x7f */
579 0x1a000003, /* bne done */
580 0xe2522001, /* subs r2, r2, #1 */
581 0x0a000001, /* beq done */
582 0xe2811002, /* add r1, r1 #2 */
583 0xeafffff3, /* b loop */
584 0xeafffffe, /* done: b -2 */
587 u32 word_8_code
[] = {
588 0xe4d04001, /* loop: ldrb r4, [r0], #1 */
589 0xe5c13000, /* strb r3, [r1] */
590 0xe5c14000, /* strb r4, [r1] */
591 0xe5d14000, /* busy ldrb r4, [r1] */
592 0xe3140080, /* tst r4, #0x80 */
593 0x0afffffc, /* beq busy */
594 0xe314007f, /* tst r4, #0x7f */
595 0x1a000003, /* bne done */
596 0xe2522001, /* subs r2, r2, #1 */
597 0x0a000001, /* beq done */
598 0xe2811001, /* add r1, r1 #1 */
599 0xeafffff3, /* b loop */
600 0xeafffffe, /* done: b -2 */
603 cfi_intel_clear_status_register(bank
);
605 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
606 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
607 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
609 /* flash write code */
610 if (!cfi_info
->write_algorithm
)
612 if (target_alloc_working_area(target
, 4 * 13, &cfi_info
->write_algorithm
) != ERROR_OK
)
614 WARNING("no working area available, can't do block memory writes");
615 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
618 /* write algorithm code to working area */
619 if (bank
->bus_width
== 1)
621 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_8_code
);
623 else if (bank
->bus_width
== 2)
625 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_16_code
);
627 else if (bank
->bus_width
== 4)
629 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_32_code
);
633 return ERROR_FLASH_OPERATION_FAILED
;
637 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
640 if (buffer_size
<= 256)
642 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
643 if (cfi_info
->write_algorithm
)
644 target_free_working_area(target
, cfi_info
->write_algorithm
);
646 WARNING("no large enough working area available, can't do block memory writes");
647 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
651 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
652 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
653 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
654 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
655 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
659 u32 thisrun_count
= (count
> buffer_size
) ? buffer_size
: count
;
661 target_write_buffer(target
, source
->address
, thisrun_count
, buffer
);
663 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
664 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
665 buf_set_u32(reg_params
[2].value
, 0, 32, thisrun_count
/ bank
->bus_width
);
666 cfi_command(bank
, 0x40, write_command
);
667 buf_set_u32(reg_params
[3].value
, 0, 32, buf_get_u32(write_command
, 0, 32));
669 if ((retval
= target
->type
->run_algorithm(target
, 0, NULL
, 5, reg_params
, cfi_info
->write_algorithm
->address
, cfi_info
->write_algorithm
->address
+ (12 * 4), 10000, &armv4_5_info
)) != ERROR_OK
)
671 cfi_intel_clear_status_register(bank
);
672 return ERROR_FLASH_OPERATION_FAILED
;
675 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x80)
677 /* read status register (outputs debug inforation) */
678 cfi_intel_wait_status_busy(bank
, 100);
679 cfi_intel_clear_status_register(bank
);
680 return ERROR_FLASH_OPERATION_FAILED
;
683 buffer
+= thisrun_count
;
684 address
+= thisrun_count
;
685 count
-= thisrun_count
;
688 destroy_reg_param(®_params
[0]);
689 destroy_reg_param(®_params
[1]);
690 destroy_reg_param(®_params
[2]);
691 destroy_reg_param(®_params
[3]);
692 destroy_reg_param(®_params
[4]);
697 int cfi_intel_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
699 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
700 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
701 target_t
*target
= cfi_info
->target
;
704 cfi_intel_clear_status_register(bank
);
705 cfi_command(bank
, 0x40, command
);
706 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, command
);
708 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, word
);
710 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->word_write_timeout_max
)) != 0x80)
712 cfi_command(bank
, 0xff, command
);
713 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
715 ERROR("couldn't write word at base 0x%x, address %x", bank
->base
, address
);
716 return ERROR_FLASH_OPERATION_FAILED
;
722 int cfi_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
724 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
725 target_t
*target
= cfi_info
->target
;
727 switch(cfi_info
->pri_id
)
731 return cfi_intel_write_word(bank
, word
, address
);
734 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
738 return ERROR_FLASH_OPERATION_FAILED
;
741 int cfi_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
743 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
744 target_t
*target
= cfi_info
->target
;
745 u32 address
= bank
->base
+ offset
; /* address of first byte to be programmed */
747 int align
; /* number of unaligned bytes */
748 u8 current_word
[CFI_MAX_BUS_WIDTH
* 4]; /* word (bus_width size) currently being programmed */
752 if (cfi_info
->target
->state
!= TARGET_HALTED
)
754 return ERROR_TARGET_NOT_HALTED
;
757 if (offset
+ count
> bank
->size
)
758 return ERROR_FLASH_DST_OUT_OF_BANK
;
760 if (cfi_info
->qry
[0] != 'Q')
761 return ERROR_FLASH_BANK_NOT_PROBED
;
763 /* start at the first byte of the first word (bus_width size) */
764 write_p
= address
& ~(bank
->bus_width
- 1);
765 if ((align
= address
- write_p
) != 0)
767 for (i
= 0; i
< bank
->bus_width
; i
++)
771 /* copy bytes before the first write address */
772 for (i
= 0; i
< align
; ++i
, ++copy_p
)
775 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
776 cfi_add_byte(bank
, current_word
, byte
);
779 /* add bytes from the buffer */
780 for (; (i
< bank
->bus_width
) && (count
> 0); i
++)
782 cfi_add_byte(bank
, current_word
, *buffer
++);
787 /* if the buffer is already finished, copy bytes after the last write address */
788 for (; (count
== 0) && (i
< bank
->bus_width
); ++i
, ++copy_p
)
791 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
792 cfi_add_byte(bank
, current_word
, byte
);
795 retval
= cfi_write_word(bank
, current_word
, write_p
);
796 if (retval
!= ERROR_OK
)
801 /* handle blocks of bus_size aligned bytes */
802 switch(cfi_info
->pri_id
)
804 /* try block writes (fails without working area) */
807 retval
= cfi_intel_write_block(bank
, buffer
, write_p
, count
);
810 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
813 if (retval
!= ERROR_OK
)
815 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
817 /* fall back to memory writes */
818 while (count
> bank
->bus_width
)
820 for (i
= 0; i
< bank
->bus_width
; i
++)
823 for (i
= 0; i
< bank
->bus_width
; i
++)
825 cfi_add_byte(bank
, current_word
, *buffer
++);
828 retval
= cfi_write_word(bank
, current_word
, write_p
);
829 if (retval
!= ERROR_OK
)
831 write_p
+= bank
->bus_width
;
832 count
-= bank
->bus_width
;
839 /* handle unaligned tail bytes */
843 for (i
= 0; i
< bank
->bus_width
; i
++)
846 for (i
= 0; (i
< bank
->bus_width
) && (count
> 0); ++i
, ++copy_p
)
848 cfi_add_byte(bank
, current_word
, *buffer
++);
851 for (; i
< bank
->bus_width
; ++i
, ++copy_p
)
854 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
855 cfi_add_byte(bank
, current_word
, byte
);
857 retval
= cfi_write_word(bank
, current_word
, write_p
);
858 if (retval
!= ERROR_OK
)
862 /* return to read array mode */
863 cfi_command(bank
, 0xf0, current_word
);
864 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
865 cfi_command(bank
, 0xff, current_word
);
866 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
871 int cfi_probe(struct flash_bank_s
*bank
)
873 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
874 target_t
*target
= cfi_info
->target
;
878 cfi_command(bank
, 0x98, command
);
879 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
881 cfi_info
->qry
[0] = cfi_query_u8(bank
, 0, 0x10);
882 cfi_info
->qry
[1] = cfi_query_u8(bank
, 0, 0x11);
883 cfi_info
->qry
[2] = cfi_query_u8(bank
, 0, 0x12);
885 if ((cfi_info
->qry
[0] != 'Q') || (cfi_info
->qry
[1] != 'R') || (cfi_info
->qry
[2] != 'Y'))
887 cfi_command(bank
, 0xf0, command
);
888 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
889 cfi_command(bank
, 0xff, command
);
890 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
891 return ERROR_FLASH_BANK_INVALID
;
894 cfi_info
->pri_id
= cfi_query_u16(bank
, 0, 0x13);
895 cfi_info
->pri_addr
= cfi_query_u16(bank
, 0, 0x15);
896 cfi_info
->alt_id
= cfi_query_u16(bank
, 0, 0x17);
897 cfi_info
->alt_addr
= cfi_query_u16(bank
, 0, 0x19);
899 DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info
->qry
[0], cfi_info
->qry
[1], cfi_info
->qry
[2], cfi_info
->pri_id
, cfi_info
->pri_addr
, cfi_info
->alt_id
, cfi_info
->alt_addr
);
901 cfi_info
->vcc_min
= cfi_query_u8(bank
, 0, 0x1b);
902 cfi_info
->vcc_max
= cfi_query_u8(bank
, 0, 0x1c);
903 cfi_info
->vpp_min
= cfi_query_u8(bank
, 0, 0x1d);
904 cfi_info
->vpp_max
= cfi_query_u8(bank
, 0, 0x1e);
905 cfi_info
->word_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x1f);
906 cfi_info
->buf_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x20);
907 cfi_info
->block_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x21);
908 cfi_info
->chip_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x22);
909 cfi_info
->word_write_timeout_max
= cfi_query_u8(bank
, 0, 0x23);
910 cfi_info
->buf_write_timeout_max
= cfi_query_u8(bank
, 0, 0x24);
911 cfi_info
->block_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x25);
912 cfi_info
->chip_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x26);
914 DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
915 (cfi_info
->vcc_min
& 0xf0) >> 4, cfi_info
->vcc_min
& 0x0f,
916 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
917 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
918 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
919 DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info
->word_write_timeout_typ
, 1 << cfi_info
->buf_write_timeout_typ
,
920 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
921 DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info
->word_write_timeout_max
) * (1 << cfi_info
->word_write_timeout_typ
),
922 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
923 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
924 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
926 cfi_info
->dev_size
= cfi_query_u8(bank
, 0, 0x27);
927 cfi_info
->interface_desc
= cfi_query_u16(bank
, 0, 0x28);
928 cfi_info
->max_buf_write_size
= cfi_query_u16(bank
, 0, 0x2a);
929 cfi_info
->num_erase_regions
= cfi_query_u8(bank
, 0, 0x2c);
931 DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info
->dev_size
, cfi_info
->interface_desc
, cfi_info
->max_buf_write_size
);
933 if (1 << cfi_info
->dev_size
!= bank
->size
)
935 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank
->size
, 1 << cfi_info
->dev_size
);
938 if (cfi_info
->num_erase_regions
)
944 cfi_info
->erase_region_info
= malloc(4 * cfi_info
->num_erase_regions
);
946 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
948 cfi_info
->erase_region_info
[i
] = cfi_query_u32(bank
, 0, 0x2d + (4 * i
));
949 DEBUG("erase region[%i]: %i blocks of size 0x%x", i
, (cfi_info
->erase_region_info
[i
] & 0xffff) + 1, (cfi_info
->erase_region_info
[i
] >> 16) * 256);
951 num_sectors
+= (cfi_info
->erase_region_info
[i
] & 0xffff) + 1;
954 bank
->num_sectors
= num_sectors
;
955 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
956 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
959 for (j
= 0; j
< (cfi_info
->erase_region_info
[i
] & 0xffff) + 1; j
++)
961 bank
->sectors
[sector
].offset
= offset
;
962 bank
->sectors
[sector
].size
= (cfi_info
->erase_region_info
[i
] >> 16) * 256;
963 offset
+= bank
->sectors
[sector
].size
;
964 bank
->sectors
[sector
].is_erased
= -1;
965 bank
->sectors
[sector
].is_protected
= -1;
972 cfi_info
->erase_region_info
= NULL
;
975 switch(cfi_info
->pri_id
)
979 cfi_read_intel_pri_ext(bank
);
982 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
986 /* return to read array mode */
987 cfi_command(bank
, 0xf0, command
);
988 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
989 cfi_command(bank
, 0xff, command
);
990 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
995 int cfi_erase_check(struct flash_bank_s
*bank
)
997 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
998 target_t
*target
= cfi_info
->target
;
1002 if (!cfi_info
->erase_check_algorithm
)
1004 u32 erase_check_code
[] =
1013 /* make sure we have a working area */
1014 if (target_alloc_working_area(target
, 20, &cfi_info
->erase_check_algorithm
) != ERROR_OK
)
1016 WARNING("no working area available, falling back to slow memory reads");
1020 /* write algorithm code to working area */
1021 target
->type
->write_memory(target
, cfi_info
->erase_check_algorithm
->address
, 4, 5, (u8
*)erase_check_code
);
1025 if (!cfi_info
->erase_check_algorithm
)
1027 u32
*buffer
= malloc(4096);
1029 for (i
= 0; i
< bank
->num_sectors
; i
++)
1031 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1032 u32 size
= bank
->sectors
[i
].size
;
1033 u32 check
= 0xffffffffU
;
1038 u32 thisrun_size
= (size
> 4096) ? 4096 : size
;
1041 target
->type
->read_memory(target
, address
, 4, thisrun_size
/ 4, (u8
*)buffer
);
1043 for (j
= 0; j
< thisrun_size
/ 4; j
++)
1046 if (check
!= 0xffffffff)
1052 size
-= thisrun_size
;
1053 address
+= thisrun_size
;
1056 bank
->sectors
[i
].is_erased
= erased
;
1063 for (i
= 0; i
< bank
->num_sectors
; i
++)
1065 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1066 u32 size
= bank
->sectors
[i
].size
;
1068 reg_param_t reg_params
[3];
1069 armv4_5_algorithm_t armv4_5_info
;
1071 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
1072 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
1073 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
1075 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
1076 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
1078 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
1079 buf_set_u32(reg_params
[1].value
, 0, 32, size
);
1081 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
1082 buf_set_u32(reg_params
[2].value
, 0, 32, 0xff);
1084 if ((retval
= target
->type
->run_algorithm(target
, 0, NULL
, 3, reg_params
, cfi_info
->erase_check_algorithm
->address
, cfi_info
->erase_check_algorithm
->address
+ 0x10, 10000, &armv4_5_info
)) != ERROR_OK
)
1085 return ERROR_FLASH_OPERATION_FAILED
;
1087 if (buf_get_u32(reg_params
[2].value
, 0, 32) == 0xff)
1088 bank
->sectors
[i
].is_erased
= 1;
1090 bank
->sectors
[i
].is_erased
= 0;
1092 destroy_reg_param(®_params
[0]);
1093 destroy_reg_param(®_params
[1]);
1094 destroy_reg_param(®_params
[2]);
1101 int cfi_intel_protect_check(struct flash_bank_s
*bank
)
1103 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1104 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
1105 target_t
*target
= cfi_info
->target
;
1109 /* check if block lock bits are supported on this device */
1110 if (!(pri_ext
->blk_status_reg_mask
& 0x1))
1111 return ERROR_FLASH_OPERATION_FAILED
;
1113 cfi_command(bank
, 0x90, command
);
1114 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
1116 for (i
= 0; i
< bank
->num_sectors
; i
++)
1118 u8 block_status
= cfi_get_u8(bank
, i
, 0x2);
1120 if (block_status
& 1)
1121 bank
->sectors
[i
].is_protected
= 1;
1123 bank
->sectors
[i
].is_protected
= 0;
1126 cfi_command(bank
, 0xff, command
);
1127 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
1132 int cfi_protect_check(struct flash_bank_s
*bank
)
1134 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1135 target_t
*target
= cfi_info
->target
;
1137 if (cfi_info
->qry
[0] != 'Q')
1138 return ERROR_FLASH_BANK_NOT_PROBED
;
1140 switch(cfi_info
->pri_id
)
1144 return cfi_intel_protect_check(bank
);
1147 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
1154 int cfi_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
1157 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1159 if (cfi_info
->qry
[0] == -1)
1161 printed
= snprintf(buf
, buf_size
, "\ncfi flash bank not probed yet\n");
1165 printed
= snprintf(buf
, buf_size
, "\ncfi information:\n");
1167 buf_size
-= printed
;
1169 printed
= snprintf(buf
, buf_size
, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info
->qry
[0], cfi_info
->qry
[1], cfi_info
->qry
[2], cfi_info
->pri_id
, cfi_info
->pri_addr
, cfi_info
->alt_id
, cfi_info
->alt_addr
);
1171 buf_size
-= printed
;
1173 printed
= snprintf(buf
, buf_size
, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info
->vcc_min
& 0xf0) >> 4, cfi_info
->vcc_min
& 0x0f,
1174 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
1175 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
1176 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
1178 buf_size
-= printed
;
1180 printed
= snprintf(buf
, buf_size
, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info
->word_write_timeout_typ
, 1 << cfi_info
->buf_write_timeout_typ
,
1181 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
1183 buf_size
-= printed
;
1185 printed
= snprintf(buf
, buf_size
, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info
->word_write_timeout_max
) * (1 << cfi_info
->word_write_timeout_typ
),
1186 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
1187 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
1188 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
1190 buf_size
-= printed
;
1192 printed
= snprintf(buf
, buf_size
, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info
->dev_size
, cfi_info
->interface_desc
, cfi_info
->max_buf_write_size
);
1194 buf_size
-= printed
;
1196 switch(cfi_info
->pri_id
)
1200 cfi_intel_info(bank
, buf
, buf_size
);
1203 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
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)