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 ***************************************************************************/
26 #include "algorithm.h"
27 #include "binarybuffer.h"
34 int cfi_register_commands(struct command_context_s
*cmd_ctx
);
35 int cfi_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
);
36 int cfi_erase(struct flash_bank_s
*bank
, int first
, int last
);
37 int cfi_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
);
38 int cfi_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
);
39 int cfi_probe(struct flash_bank_s
*bank
);
40 int cfi_erase_check(struct flash_bank_s
*bank
);
41 int cfi_protect_check(struct flash_bank_s
*bank
);
42 int cfi_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
);
44 int cfi_handle_part_id_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
46 #define CFI_MAX_BUS_WIDTH 4
48 flash_driver_t cfi_flash
=
51 .register_commands
= cfi_register_commands
,
52 .flash_bank_command
= cfi_flash_bank_command
,
54 .protect
= cfi_protect
,
57 .erase_check
= cfi_erase_check
,
58 .protect_check
= cfi_protect_check
,
62 inline u32
flash_address(flash_bank_t
*bank
, int sector
, u32 offset
)
64 /* while the sector list isn't built, only accesses to sector 0 work */
66 return bank
->base
+ offset
* bank
->bus_width
;
71 ERROR("BUG: sector list not yet built");
74 return bank
->base
+ bank
->sectors
[sector
].offset
+ offset
* bank
->bus_width
;
79 void cfi_command(flash_bank_t
*bank
, u8 cmd
, u8
*cmd_buf
)
81 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
84 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
86 for (i
= bank
->bus_width
; i
> 0; i
--)
88 *cmd_buf
++ = (i
& (bank
->chip_width
- 1)) ? 0x0 : cmd
;
93 for (i
= 1; i
<= bank
->bus_width
; i
++)
95 *cmd_buf
++ = (i
& (bank
->chip_width
- 1)) ? 0x0 : cmd
;
100 /* read unsigned 8-bit value from the bank
101 * flash banks are expected to be made of similar chips
102 * the query result should be the same for all
104 u8
cfi_query_u8(flash_bank_t
*bank
, int sector
, u32 offset
)
106 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
107 target_t
*target
= cfi_info
->target
;
108 u8 data
[CFI_MAX_BUS_WIDTH
];
110 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 1, data
);
112 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
115 return data
[bank
->bus_width
- 1];
118 /* read unsigned 8-bit value from the bank
119 * in case of a bank made of multiple chips,
120 * the individual values are ORed
122 u8
cfi_get_u8(flash_bank_t
*bank
, int sector
, u32 offset
)
124 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
125 target_t
*target
= cfi_info
->target
;
126 u8 data
[CFI_MAX_BUS_WIDTH
];
129 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 1, data
);
131 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
133 for (i
= 0; i
< bank
->bus_width
/ bank
->chip_width
; i
++)
141 for (i
= 0; i
< bank
->bus_width
/ bank
->chip_width
; i
++)
142 value
|= data
[bank
->bus_width
- 1 - i
];
148 u16
cfi_query_u16(flash_bank_t
*bank
, int sector
, u32 offset
)
150 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
151 target_t
*target
= cfi_info
->target
;
152 u8 data
[CFI_MAX_BUS_WIDTH
* 2];
154 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 2, data
);
156 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
157 return data
[0] | data
[bank
->bus_width
] << 8;
159 return data
[bank
->bus_width
- 1] | data
[(2 * bank
->bus_width
) - 1] << 8;
162 u32
cfi_query_u32(flash_bank_t
*bank
, int sector
, u32 offset
)
164 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
165 target_t
*target
= cfi_info
->target
;
166 u8 data
[CFI_MAX_BUS_WIDTH
* 4];
168 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 4, data
);
170 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
171 return data
[0] | data
[bank
->bus_width
] << 8 | data
[bank
->bus_width
* 2] << 16 | data
[bank
->bus_width
* 3] << 24;
173 return data
[bank
->bus_width
- 1] | data
[(2* bank
->bus_width
) - 1] << 8 |
174 data
[(3 * bank
->bus_width
) - 1] << 16 | data
[(4 * bank
->bus_width
) - 1] << 24;
177 void cfi_intel_clear_status_register(flash_bank_t
*bank
)
179 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
180 target_t
*target
= cfi_info
->target
;
183 if (target
->state
!= TARGET_HALTED
)
185 ERROR("BUG: attempted to clear status register while target wasn't halted");
189 cfi_command(bank
, 0x50, command
);
190 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
193 u8
cfi_intel_wait_status_busy(flash_bank_t
*bank
, int timeout
)
197 while ((!((status
= cfi_get_u8(bank
, 0, 0x0)) & 0x80)) && (timeout
-- > 0))
199 DEBUG("status: 0x%x", status
);
203 DEBUG("status: 0x%x", status
);
207 ERROR("status register: 0x%x", status
);
209 ERROR("Block Lock-Bit Detected, Operation Abort");
211 ERROR("Program suspended");
213 ERROR("Low Programming Voltage Detected, Operation Aborted");
215 ERROR("Program Error / Error in Setting Lock-Bit");
217 ERROR("Error in Block Erasure or Clear Lock-Bits");
219 ERROR("Block Erase Suspended");
221 cfi_intel_clear_status_register(bank
);
226 int cfi_read_intel_pri_ext(flash_bank_t
*bank
)
228 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
229 cfi_intel_pri_ext_t
*pri_ext
= malloc(sizeof(cfi_intel_pri_ext_t
));
230 target_t
*target
= cfi_info
->target
;
233 cfi_info
->pri_ext
= pri_ext
;
235 pri_ext
->pri
[0] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0);
236 pri_ext
->pri
[1] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 1);
237 pri_ext
->pri
[2] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 2);
239 if ((pri_ext
->pri
[0] != 'P') || (pri_ext
->pri
[1] != 'R') || (pri_ext
->pri
[2] != 'I'))
241 cfi_command(bank
, 0xf0, command
);
242 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
243 cfi_command(bank
, 0xff, command
);
244 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
245 return ERROR_FLASH_BANK_INVALID
;
248 pri_ext
->major_version
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 3);
249 pri_ext
->minor_version
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 4);
251 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
);
253 pri_ext
->feature_support
= cfi_query_u32(bank
, 0, cfi_info
->pri_addr
+ 5);
254 pri_ext
->suspend_cmd_support
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 9);
255 pri_ext
->blk_status_reg_mask
= cfi_query_u16(bank
, 0, cfi_info
->pri_addr
+ 0xa);
257 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
);
259 pri_ext
->vcc_optimal
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xc);
260 pri_ext
->vpp_optimal
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xd);
262 DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
263 (pri_ext
->vcc_optimal
& 0xf0) >> 4, pri_ext
->vcc_optimal
& 0x0f,
264 (pri_ext
->vpp_optimal
& 0xf0) >> 4, pri_ext
->vpp_optimal
& 0x0f);
266 pri_ext
->num_protection_fields
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xe);
267 if (pri_ext
->num_protection_fields
!= 1)
269 WARNING("expected one protection register field, but found %i", pri_ext
->num_protection_fields
);
272 pri_ext
->prot_reg_addr
= cfi_query_u16(bank
, 0, cfi_info
->pri_addr
+ 0xf);
273 pri_ext
->fact_prot_reg_size
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0x11);
274 pri_ext
->user_prot_reg_size
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0x12);
276 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
);
281 int cfi_intel_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
284 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
285 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
287 printed
= snprintf(buf
, buf_size
, "\nintel primary algorithm extend information:\n");
291 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
);
295 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
);
299 printed
= snprintf(buf
, buf_size
, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
300 (pri_ext
->vcc_optimal
& 0xf0) >> 4, pri_ext
->vcc_optimal
& 0x0f,
301 (pri_ext
->vpp_optimal
& 0xf0) >> 4, pri_ext
->vpp_optimal
& 0x0f);
305 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
);
310 int cfi_register_commands(struct command_context_s
*cmd_ctx
)
312 command_t
*cfi_cmd
= register_command(cmd_ctx
, NULL
, "cfi", NULL
, COMMAND_ANY
, NULL
);
314 register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
315 "print part id of cfi flash bank <num>");
320 /* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#>
322 int cfi_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
)
324 cfi_flash_bank_t
*cfi_info
;
328 WARNING("incomplete flash_bank cfi configuration");
329 return ERROR_FLASH_BANK_INVALID
;
332 cfi_info
= malloc(sizeof(cfi_flash_bank_t
));
333 bank
->driver_priv
= cfi_info
;
335 cfi_info
->target
= get_target_by_num(strtoul(args
[5], NULL
, 0));
336 if (!cfi_info
->target
)
338 ERROR("no target '%i' configured", args
[5]);
342 /* bank wasn't probed yet */
343 cfi_info
->qry
[0] = -1;
348 int cfi_intel_erase(struct flash_bank_s
*bank
, int first
, int last
)
350 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
351 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
352 target_t
*target
= cfi_info
->target
;
356 cfi_intel_clear_status_register(bank
);
358 for (i
= first
; i
<= last
; i
++)
360 cfi_command(bank
, 0x20, command
);
361 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
363 cfi_command(bank
, 0xd0, command
);
364 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
366 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->block_erase_timeout_typ
)) == 0x80)
367 bank
->sectors
[i
].is_erased
= 1;
370 cfi_command(bank
, 0xff, command
);
371 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
373 ERROR("couldn't erase block %i of flash bank at base 0x%x", i
, bank
->base
);
374 return ERROR_FLASH_OPERATION_FAILED
;
378 cfi_command(bank
, 0xff, command
);
379 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
384 int cfi_erase(struct flash_bank_s
*bank
, int first
, int last
)
386 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
388 if (cfi_info
->target
->state
!= TARGET_HALTED
)
390 return ERROR_TARGET_NOT_HALTED
;
393 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
395 return ERROR_FLASH_SECTOR_INVALID
;
398 if (cfi_info
->qry
[0] != 'Q')
399 return ERROR_FLASH_BANK_NOT_PROBED
;
401 switch(cfi_info
->pri_id
)
405 return cfi_intel_erase(bank
, first
, last
);
408 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
415 int cfi_intel_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
417 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
418 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
419 target_t
*target
= cfi_info
->target
;
423 if (!(pri_ext
->feature_support
& 0x28))
424 return ERROR_FLASH_OPERATION_FAILED
;
426 cfi_intel_clear_status_register(bank
);
428 for (i
= first
; i
<= last
; i
++)
430 cfi_command(bank
, 0x60, command
);
431 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
434 cfi_command(bank
, 0x01, command
);
435 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
436 bank
->sectors
[i
].is_protected
= 1;
440 cfi_command(bank
, 0xd0, command
);
441 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
442 bank
->sectors
[i
].is_protected
= 0;
445 cfi_intel_wait_status_busy(bank
, 100);
448 /* if the device doesn't support individual block lock bits set/clear,
449 * all blocks have been unlocked in parallel, so we set those that should be protected
451 if ((!set
) && (!(pri_ext
->feature_support
& 0x20)))
453 for (i
= 0; i
< bank
->num_sectors
; i
++)
455 cfi_intel_clear_status_register(bank
);
456 cfi_command(bank
, 0x60, command
);
457 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
458 if (bank
->sectors
[i
].is_protected
== 1)
460 cfi_command(bank
, 0x01, command
);
461 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
464 cfi_intel_wait_status_busy(bank
, 100);
468 cfi_command(bank
, 0xff, command
);
469 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
474 int cfi_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
476 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
478 if (cfi_info
->target
->state
!= TARGET_HALTED
)
480 return ERROR_TARGET_NOT_HALTED
;
483 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
485 return ERROR_FLASH_SECTOR_INVALID
;
488 if (cfi_info
->qry
[0] != 'Q')
489 return ERROR_FLASH_BANK_NOT_PROBED
;
491 switch(cfi_info
->pri_id
)
495 cfi_intel_protect(bank
, set
, first
, last
);
498 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
505 void cfi_add_byte(struct flash_bank_s
*bank
, u8
*word
, u8 byte
)
507 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
508 target_t
*target
= cfi_info
->target
;
512 if (target
->endianness
== TARGET_LITTLE_ENDIAN
)
515 for (i
= 0; i
< bank
->bus_width
- 1; i
++)
516 word
[i
] = word
[i
+ 1];
517 word
[bank
->bus_width
- 1] = byte
;
522 for (i
= bank
->bus_width
- 1; i
> 0; i
--)
523 word
[i
] = word
[i
- 1];
528 int cfi_intel_write_block(struct flash_bank_s
*bank
, u8
*buffer
, u32 address
, u32 count
)
530 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
531 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
532 target_t
*target
= cfi_info
->target
;
533 reg_param_t reg_params
[5];
534 armv4_5_algorithm_t armv4_5_info
;
535 working_area_t
*source
;
536 u32 buffer_size
= 32768;
537 u8 write_command
[CFI_MAX_BUS_WIDTH
];
541 u32 word_32_code
[] = {
542 0xe4904004, /* loop: ldr r4, [r0], #4 */
543 0xe5813000, /* str r3, [r1] */
544 0xe5814000, /* str r4, [r1] */
545 0xe5914000, /* busy ldr r4, [r1] */
546 0xe3140080, /* tst r4, #0x80 */
547 0x0afffffc, /* beq busy */
548 0xe314007f, /* tst r4, #0x7f */
549 0x1a000003, /* bne done */
550 0xe2522001, /* subs r2, r2, #1 */
551 0x0a000001, /* beq done */
552 0xe2811004, /* add r1, r1 #4 */
553 0xeafffff3, /* b loop */
554 0xeafffffe, /* done: b -2 */
557 u32 word_16_code
[] = {
558 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
559 0xe1c130b0, /* strh r3, [r1] */
560 0xe1c140b0, /* strh r4, [r1] */
561 0xe1d140b0, /* busy ldrh r4, [r1] */
562 0xe3140080, /* tst r4, #0x80 */
563 0x0afffffc, /* beq busy */
564 0xe314007f, /* tst r4, #0x7f */
565 0x1a000003, /* bne done */
566 0xe2522001, /* subs r2, r2, #1 */
567 0x0a000001, /* beq done */
568 0xe2811002, /* add r1, r1 #2 */
569 0xeafffff3, /* b loop */
570 0xeafffffe, /* done: b -2 */
573 u32 word_8_code
[] = {
574 0xe4d04001, /* loop: ldrb r4, [r0], #1 */
575 0xe5c13000, /* strb r3, [r1] */
576 0xe5c14000, /* strb r4, [r1] */
577 0xe5d14000, /* busy ldrb r4, [r1] */
578 0xe3140080, /* tst r4, #0x80 */
579 0x0afffffc, /* beq busy */
580 0xe314007f, /* tst r4, #0x7f */
581 0x1a000003, /* bne done */
582 0xe2522001, /* subs r2, r2, #1 */
583 0x0a000001, /* beq done */
584 0xe2811001, /* add r1, r1 #1 */
585 0xeafffff3, /* b loop */
586 0xeafffffe, /* done: b -2 */
589 cfi_intel_clear_status_register(bank
);
591 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
592 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
593 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
595 /* flash write code */
596 if (!cfi_info
->write_algorithm
)
598 if (target_alloc_working_area(target
, 4 * 13, &cfi_info
->write_algorithm
) != ERROR_OK
)
600 WARNING("no working area available, can't do block memory writes");
601 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
604 /* write algorithm code to working area */
605 if (bank
->bus_width
== 1)
607 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_8_code
);
609 else if (bank
->bus_width
== 2)
611 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_16_code
);
613 else if (bank
->bus_width
== 4)
615 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_32_code
);
619 return ERROR_FLASH_OPERATION_FAILED
;
623 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
626 if (buffer_size
<= 256)
628 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
629 if (cfi_info
->write_algorithm
)
630 target_free_working_area(target
, cfi_info
->write_algorithm
);
632 WARNING("no large enough working area available, can't do block memory writes");
633 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
637 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
638 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
639 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
640 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
641 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
645 u32 thisrun_count
= (count
> buffer_size
) ? buffer_size
: count
;
647 target_write_buffer(target
, source
->address
, thisrun_count
, buffer
);
649 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
650 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
651 buf_set_u32(reg_params
[2].value
, 0, 32, thisrun_count
/ bank
->bus_width
);
652 cfi_command(bank
, 0x40, write_command
);
653 buf_set_u32(reg_params
[3].value
, 0, 32, buf_get_u32(write_command
, 0, 32));
655 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
)
657 cfi_intel_clear_status_register(bank
);
658 return ERROR_FLASH_OPERATION_FAILED
;
661 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x80)
663 /* read status register (outputs debug inforation) */
664 cfi_intel_wait_status_busy(bank
, 100);
665 cfi_intel_clear_status_register(bank
);
666 return ERROR_FLASH_OPERATION_FAILED
;
669 buffer
+= thisrun_count
;
670 address
+= thisrun_count
;
671 count
-= thisrun_count
;
674 destroy_reg_param(®_params
[0]);
675 destroy_reg_param(®_params
[1]);
676 destroy_reg_param(®_params
[2]);
677 destroy_reg_param(®_params
[3]);
678 destroy_reg_param(®_params
[4]);
683 int cfi_intel_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
685 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
686 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
687 target_t
*target
= cfi_info
->target
;
690 cfi_intel_clear_status_register(bank
);
691 cfi_command(bank
, 0x40, command
);
692 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, command
);
694 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, word
);
696 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->word_write_timeout_max
)) != 0x80)
698 cfi_command(bank
, 0xff, command
);
699 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
701 ERROR("couldn't write word at base 0x%x, address %x", bank
->base
, address
);
702 return ERROR_FLASH_OPERATION_FAILED
;
708 int cfi_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
710 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
711 target_t
*target
= cfi_info
->target
;
713 switch(cfi_info
->pri_id
)
717 return cfi_intel_write_word(bank
, word
, address
);
720 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
724 return ERROR_FLASH_OPERATION_FAILED
;
727 int cfi_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
729 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
730 target_t
*target
= cfi_info
->target
;
731 u32 address
= bank
->base
+ offset
; /* address of first byte to be programmed */
733 int align
; /* number of unaligned bytes */
734 u8 current_word
[CFI_MAX_BUS_WIDTH
* 4]; /* word (bus_width size) currently being programmed */
738 if (cfi_info
->target
->state
!= TARGET_HALTED
)
740 return ERROR_TARGET_NOT_HALTED
;
743 if (offset
+ count
> bank
->size
)
744 return ERROR_FLASH_DST_OUT_OF_BANK
;
746 if (cfi_info
->qry
[0] != 'Q')
747 return ERROR_FLASH_BANK_NOT_PROBED
;
749 /* start at the first byte of the first word (bus_width size) */
750 write_p
= address
& ~(bank
->bus_width
- 1);
751 if ((align
= address
- write_p
) != 0)
753 for (i
= 0; i
< bank
->bus_width
; i
++)
757 /* copy bytes before the first write address */
758 for (i
= 0; i
< align
; ++i
, ++copy_p
)
761 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
762 cfi_add_byte(bank
, current_word
, byte
);
765 /* add bytes from the buffer */
766 for (; (i
< bank
->bus_width
) && (count
> 0); i
++)
768 cfi_add_byte(bank
, current_word
, *buffer
++);
773 /* if the buffer is already finished, copy bytes after the last write address */
774 for (; (count
== 0) && (i
< bank
->bus_width
); ++i
, ++copy_p
)
777 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
778 cfi_add_byte(bank
, current_word
, byte
);
781 retval
= cfi_write_word(bank
, current_word
, write_p
);
782 if (retval
!= ERROR_OK
)
787 /* handle blocks of bus_size aligned bytes */
788 switch(cfi_info
->pri_id
)
790 /* try block writes (fails without working area) */
793 retval
= cfi_intel_write_block(bank
, buffer
, write_p
, count
);
796 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
799 if (retval
!= ERROR_OK
)
801 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
803 /* fall back to memory writes */
804 while (count
> bank
->bus_width
)
806 for (i
= 0; i
< bank
->bus_width
; i
++)
809 for (i
= 0; i
< bank
->bus_width
; i
++)
811 cfi_add_byte(bank
, current_word
, *buffer
++);
814 retval
= cfi_write_word(bank
, current_word
, write_p
);
815 if (retval
!= ERROR_OK
)
817 write_p
+= bank
->bus_width
;
818 count
-= bank
->bus_width
;
825 /* handle unaligned tail bytes */
829 for (i
= 0; i
< bank
->bus_width
; i
++)
832 for (i
= 0; (i
< bank
->bus_width
) && (count
> 0); ++i
, ++copy_p
)
834 cfi_add_byte(bank
, current_word
, *buffer
++);
837 for (; i
< bank
->bus_width
; ++i
, ++copy_p
)
840 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
841 cfi_add_byte(bank
, current_word
, byte
);
843 retval
= cfi_write_word(bank
, current_word
, write_p
);
844 if (retval
!= ERROR_OK
)
848 /* return to read array mode */
849 cfi_command(bank
, 0xf0, current_word
);
850 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
851 cfi_command(bank
, 0xff, current_word
);
852 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
857 int cfi_probe(struct flash_bank_s
*bank
)
859 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
860 target_t
*target
= cfi_info
->target
;
864 cfi_command(bank
, 0x98, command
);
865 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
867 cfi_info
->qry
[0] = cfi_query_u8(bank
, 0, 0x10);
868 cfi_info
->qry
[1] = cfi_query_u8(bank
, 0, 0x11);
869 cfi_info
->qry
[2] = cfi_query_u8(bank
, 0, 0x12);
871 if ((cfi_info
->qry
[0] != 'Q') || (cfi_info
->qry
[1] != 'R') || (cfi_info
->qry
[2] != 'Y'))
873 cfi_command(bank
, 0xf0, command
);
874 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
875 cfi_command(bank
, 0xff, command
);
876 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
877 return ERROR_FLASH_BANK_INVALID
;
880 cfi_info
->pri_id
= cfi_query_u16(bank
, 0, 0x13);
881 cfi_info
->pri_addr
= cfi_query_u16(bank
, 0, 0x15);
882 cfi_info
->alt_id
= cfi_query_u16(bank
, 0, 0x17);
883 cfi_info
->alt_addr
= cfi_query_u16(bank
, 0, 0x19);
885 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
);
887 cfi_info
->vcc_min
= cfi_query_u8(bank
, 0, 0x1b);
888 cfi_info
->vcc_max
= cfi_query_u8(bank
, 0, 0x1c);
889 cfi_info
->vpp_min
= cfi_query_u8(bank
, 0, 0x1d);
890 cfi_info
->vpp_max
= cfi_query_u8(bank
, 0, 0x1e);
891 cfi_info
->word_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x1f);
892 cfi_info
->buf_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x20);
893 cfi_info
->block_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x21);
894 cfi_info
->chip_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x22);
895 cfi_info
->word_write_timeout_max
= cfi_query_u8(bank
, 0, 0x23);
896 cfi_info
->buf_write_timeout_max
= cfi_query_u8(bank
, 0, 0x24);
897 cfi_info
->block_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x25);
898 cfi_info
->chip_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x26);
900 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",
901 (cfi_info
->vcc_min
& 0xf0) >> 4, cfi_info
->vcc_min
& 0x0f,
902 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
903 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
904 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
905 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
,
906 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
907 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
),
908 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
909 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
910 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
912 cfi_info
->dev_size
= cfi_query_u8(bank
, 0, 0x27);
913 cfi_info
->interface_desc
= cfi_query_u16(bank
, 0, 0x28);
914 cfi_info
->max_buf_write_size
= cfi_query_u16(bank
, 0, 0x2a);
915 cfi_info
->num_erase_regions
= cfi_query_u8(bank
, 0, 0x2c);
917 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
);
919 if (1 << cfi_info
->dev_size
!= bank
->size
)
921 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank
->size
, 1 << cfi_info
->dev_size
);
924 if (cfi_info
->num_erase_regions
)
930 cfi_info
->erase_region_info
= malloc(4 * cfi_info
->num_erase_regions
);
932 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
934 cfi_info
->erase_region_info
[i
] = cfi_query_u32(bank
, 0, 0x2d + (4 * i
));
935 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);
937 num_sectors
+= (cfi_info
->erase_region_info
[i
] & 0xffff) + 1;
940 bank
->num_sectors
= num_sectors
;
941 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
942 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
945 for (j
= 0; j
< (cfi_info
->erase_region_info
[i
] & 0xffff) + 1; j
++)
947 bank
->sectors
[sector
].offset
= offset
;
948 bank
->sectors
[sector
].size
= (cfi_info
->erase_region_info
[i
] >> 16) * 256;
949 offset
+= bank
->sectors
[sector
].size
;
950 bank
->sectors
[sector
].is_erased
= -1;
951 bank
->sectors
[sector
].is_protected
= -1;
958 cfi_info
->erase_region_info
= NULL
;
961 switch(cfi_info
->pri_id
)
965 cfi_read_intel_pri_ext(bank
);
968 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
972 /* return to read array mode */
973 cfi_command(bank
, 0xf0, command
);
974 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
975 cfi_command(bank
, 0xff, command
);
976 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
981 int cfi_erase_check(struct flash_bank_s
*bank
)
983 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
984 target_t
*target
= cfi_info
->target
;
988 if (!cfi_info
->erase_check_algorithm
)
990 u32 erase_check_code
[] =
999 /* make sure we have a working area */
1000 if (target_alloc_working_area(target
, 20, &cfi_info
->erase_check_algorithm
) != ERROR_OK
)
1002 WARNING("no working area available, falling back to slow memory reads");
1006 /* write algorithm code to working area */
1007 target
->type
->write_memory(target
, cfi_info
->erase_check_algorithm
->address
, 4, 5, (u8
*)erase_check_code
);
1011 if (!cfi_info
->erase_check_algorithm
)
1013 u32
*buffer
= malloc(4096);
1015 for (i
= 0; i
< bank
->num_sectors
; i
++)
1017 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1018 u32 size
= bank
->sectors
[i
].size
;
1019 u32 check
= 0xffffffffU
;
1024 u32 thisrun_size
= (size
> 4096) ? 4096 : size
;
1027 target
->type
->read_memory(target
, address
, 4, thisrun_size
/ 4, (u8
*)buffer
);
1029 for (j
= 0; j
< thisrun_size
/ 4; j
++)
1032 if (check
!= 0xffffffff)
1038 size
-= thisrun_size
;
1039 address
+= thisrun_size
;
1042 bank
->sectors
[i
].is_erased
= erased
;
1049 for (i
= 0; i
< bank
->num_sectors
; i
++)
1051 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1052 u32 size
= bank
->sectors
[i
].size
;
1054 reg_param_t reg_params
[3];
1055 armv4_5_algorithm_t armv4_5_info
;
1057 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
1058 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
1059 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
1061 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
1062 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
1064 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
1065 buf_set_u32(reg_params
[1].value
, 0, 32, size
);
1067 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
1068 buf_set_u32(reg_params
[2].value
, 0, 32, 0xff);
1070 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
)
1071 return ERROR_FLASH_OPERATION_FAILED
;
1073 if (buf_get_u32(reg_params
[2].value
, 0, 32) == 0xff)
1074 bank
->sectors
[i
].is_erased
= 1;
1076 bank
->sectors
[i
].is_erased
= 0;
1078 destroy_reg_param(®_params
[0]);
1079 destroy_reg_param(®_params
[1]);
1080 destroy_reg_param(®_params
[2]);
1087 int cfi_intel_protect_check(struct flash_bank_s
*bank
)
1089 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1090 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
1091 target_t
*target
= cfi_info
->target
;
1095 /* check if block lock bits are supported on this device */
1096 if (!(pri_ext
->blk_status_reg_mask
& 0x1))
1097 return ERROR_FLASH_OPERATION_FAILED
;
1099 cfi_command(bank
, 0x90, command
);
1100 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
1102 for (i
= 0; i
< bank
->num_sectors
; i
++)
1104 u8 block_status
= cfi_get_u8(bank
, i
, 0x2);
1106 if (block_status
& 1)
1107 bank
->sectors
[i
].is_protected
= 1;
1109 bank
->sectors
[i
].is_protected
= 0;
1112 cfi_command(bank
, 0xff, command
);
1113 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
1118 int cfi_protect_check(struct flash_bank_s
*bank
)
1120 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1121 target_t
*target
= cfi_info
->target
;
1123 if (cfi_info
->qry
[0] != 'Q')
1124 return ERROR_FLASH_BANK_NOT_PROBED
;
1126 switch(cfi_info
->pri_id
)
1130 return cfi_intel_protect_check(bank
);
1133 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
1140 int cfi_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
1143 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1145 if (cfi_info
->qry
[0] == -1)
1147 printed
= snprintf(buf
, buf_size
, "\ncfi flash bank not probed yet\n");
1151 printed
= snprintf(buf
, buf_size
, "\ncfi information:\n");
1153 buf_size
-= printed
;
1155 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
);
1157 buf_size
-= printed
;
1159 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,
1160 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
1161 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
1162 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
1164 buf_size
-= printed
;
1166 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
,
1167 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
1169 buf_size
-= printed
;
1171 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
),
1172 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
1173 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
1174 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
1176 buf_size
-= printed
;
1178 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
);
1180 buf_size
-= printed
;
1182 switch(cfi_info
->pri_id
)
1186 cfi_intel_info(bank
, buf
, buf_size
);
1189 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)