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
54 flash_driver_t cfi_flash
=
57 .register_commands
= cfi_register_commands
,
58 .flash_bank_command
= cfi_flash_bank_command
,
60 .protect
= cfi_protect
,
63 .erase_check
= cfi_erase_check
,
64 .protect_check
= cfi_protect_check
,
68 inline u32
flash_address(flash_bank_t
*bank
, int sector
, u32 offset
)
70 /* while the sector list isn't built, only accesses to sector 0 work */
72 return bank
->base
+ offset
* bank
->bus_width
;
77 ERROR("BUG: sector list not yet built");
80 return bank
->base
+ bank
->sectors
[sector
].offset
+ offset
* bank
->bus_width
;
85 void cfi_command(flash_bank_t
*bank
, u8 cmd
, u8
*cmd_buf
)
87 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
90 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
92 for (i
= bank
->bus_width
; i
> 0; i
--)
94 *cmd_buf
++ = (i
& (bank
->chip_width
- 1)) ? 0x0 : cmd
;
99 for (i
= 1; i
<= bank
->bus_width
; i
++)
101 *cmd_buf
++ = (i
& (bank
->chip_width
- 1)) ? 0x0 : cmd
;
106 /* read unsigned 8-bit value from the bank
107 * flash banks are expected to be made of similar chips
108 * the query result should be the same for all
110 u8
cfi_query_u8(flash_bank_t
*bank
, int sector
, u32 offset
)
112 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
113 target_t
*target
= cfi_info
->target
;
114 u8 data
[CFI_MAX_BUS_WIDTH
];
116 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 1, data
);
118 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
121 return data
[bank
->bus_width
- 1];
124 /* read unsigned 8-bit value from the bank
125 * in case of a bank made of multiple chips,
126 * the individual values are ORed
128 u8
cfi_get_u8(flash_bank_t
*bank
, int sector
, u32 offset
)
130 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
131 target_t
*target
= cfi_info
->target
;
132 u8 data
[CFI_MAX_BUS_WIDTH
];
135 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 1, data
);
137 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
139 for (i
= 0; i
< bank
->bus_width
/ bank
->chip_width
; i
++)
147 for (i
= 0; i
< bank
->bus_width
/ bank
->chip_width
; i
++)
148 value
|= data
[bank
->bus_width
- 1 - i
];
154 u16
cfi_query_u16(flash_bank_t
*bank
, int sector
, u32 offset
)
156 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
157 target_t
*target
= cfi_info
->target
;
158 u8 data
[CFI_MAX_BUS_WIDTH
* 2];
160 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 2, data
);
162 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
163 return data
[0] | data
[bank
->bus_width
] << 8;
165 return data
[bank
->bus_width
- 1] | data
[(2 * bank
->bus_width
) - 1] << 8;
168 u32
cfi_query_u32(flash_bank_t
*bank
, int sector
, u32 offset
)
170 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
171 target_t
*target
= cfi_info
->target
;
172 u8 data
[CFI_MAX_BUS_WIDTH
* 4];
174 target
->type
->read_memory(target
, flash_address(bank
, sector
, offset
), bank
->bus_width
, 4, data
);
176 if (cfi_info
->target
->endianness
== TARGET_LITTLE_ENDIAN
)
177 return data
[0] | data
[bank
->bus_width
] << 8 | data
[bank
->bus_width
* 2] << 16 | data
[bank
->bus_width
* 3] << 24;
179 return data
[bank
->bus_width
- 1] | data
[(2* bank
->bus_width
) - 1] << 8 |
180 data
[(3 * bank
->bus_width
) - 1] << 16 | data
[(4 * bank
->bus_width
) - 1] << 24;
183 void cfi_intel_clear_status_register(flash_bank_t
*bank
)
185 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
186 target_t
*target
= cfi_info
->target
;
189 if (target
->state
!= TARGET_HALTED
)
191 ERROR("BUG: attempted to clear status register while target wasn't halted");
195 cfi_command(bank
, 0x50, command
);
196 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
199 u8
cfi_intel_wait_status_busy(flash_bank_t
*bank
, int timeout
)
203 while ((!((status
= cfi_get_u8(bank
, 0, 0x0)) & 0x80)) && (timeout
-- > 0))
205 DEBUG("status: 0x%x", status
);
209 DEBUG("status: 0x%x", status
);
213 ERROR("status register: 0x%x", status
);
215 ERROR("Block Lock-Bit Detected, Operation Abort");
217 ERROR("Program suspended");
219 ERROR("Low Programming Voltage Detected, Operation Aborted");
221 ERROR("Program Error / Error in Setting Lock-Bit");
223 ERROR("Error in Block Erasure or Clear Lock-Bits");
225 ERROR("Block Erase Suspended");
227 cfi_intel_clear_status_register(bank
);
232 int cfi_read_intel_pri_ext(flash_bank_t
*bank
)
234 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
235 cfi_intel_pri_ext_t
*pri_ext
= malloc(sizeof(cfi_intel_pri_ext_t
));
236 target_t
*target
= cfi_info
->target
;
239 cfi_info
->pri_ext
= pri_ext
;
241 pri_ext
->pri
[0] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0);
242 pri_ext
->pri
[1] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 1);
243 pri_ext
->pri
[2] = cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 2);
245 if ((pri_ext
->pri
[0] != 'P') || (pri_ext
->pri
[1] != 'R') || (pri_ext
->pri
[2] != 'I'))
247 cfi_command(bank
, 0xf0, command
);
248 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
249 cfi_command(bank
, 0xff, command
);
250 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
251 return ERROR_FLASH_BANK_INVALID
;
254 pri_ext
->major_version
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 3);
255 pri_ext
->minor_version
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 4);
257 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
);
259 pri_ext
->feature_support
= cfi_query_u32(bank
, 0, cfi_info
->pri_addr
+ 5);
260 pri_ext
->suspend_cmd_support
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 9);
261 pri_ext
->blk_status_reg_mask
= cfi_query_u16(bank
, 0, cfi_info
->pri_addr
+ 0xa);
263 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
);
265 pri_ext
->vcc_optimal
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xc);
266 pri_ext
->vpp_optimal
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xd);
268 DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
269 (pri_ext
->vcc_optimal
& 0xf0) >> 4, pri_ext
->vcc_optimal
& 0x0f,
270 (pri_ext
->vpp_optimal
& 0xf0) >> 4, pri_ext
->vpp_optimal
& 0x0f);
272 pri_ext
->num_protection_fields
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0xe);
273 if (pri_ext
->num_protection_fields
!= 1)
275 WARNING("expected one protection register field, but found %i", pri_ext
->num_protection_fields
);
278 pri_ext
->prot_reg_addr
= cfi_query_u16(bank
, 0, cfi_info
->pri_addr
+ 0xf);
279 pri_ext
->fact_prot_reg_size
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0x11);
280 pri_ext
->user_prot_reg_size
= cfi_query_u8(bank
, 0, cfi_info
->pri_addr
+ 0x12);
282 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
);
287 int cfi_intel_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
290 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
291 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
293 printed
= snprintf(buf
, buf_size
, "\nintel primary algorithm extend information:\n");
297 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
);
301 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
);
305 printed
= snprintf(buf
, buf_size
, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
306 (pri_ext
->vcc_optimal
& 0xf0) >> 4, pri_ext
->vcc_optimal
& 0x0f,
307 (pri_ext
->vpp_optimal
& 0xf0) >> 4, pri_ext
->vpp_optimal
& 0x0f);
311 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
);
316 int cfi_register_commands(struct command_context_s
*cmd_ctx
)
318 command_t
*cfi_cmd
= register_command(cmd_ctx
, NULL
, "cfi", NULL
, COMMAND_ANY
, NULL
);
320 register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
321 "print part id of cfi flash bank <num>");
326 /* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#>
328 int cfi_flash_bank_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
, struct flash_bank_s
*bank
)
330 cfi_flash_bank_t
*cfi_info
;
334 WARNING("incomplete flash_bank cfi configuration");
335 return ERROR_FLASH_BANK_INVALID
;
338 cfi_info
= malloc(sizeof(cfi_flash_bank_t
));
339 bank
->driver_priv
= cfi_info
;
341 cfi_info
->target
= get_target_by_num(strtoul(args
[5], NULL
, 0));
342 if (!cfi_info
->target
)
344 ERROR("no target '%i' configured", args
[5]);
348 /* bank wasn't probed yet */
349 cfi_info
->qry
[0] = -1;
354 int cfi_intel_erase(struct flash_bank_s
*bank
, int first
, int last
)
356 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
357 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
358 target_t
*target
= cfi_info
->target
;
362 cfi_intel_clear_status_register(bank
);
364 for (i
= first
; i
<= last
; i
++)
366 cfi_command(bank
, 0x20, command
);
367 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
369 cfi_command(bank
, 0xd0, command
);
370 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
372 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->block_erase_timeout_typ
)) == 0x80)
373 bank
->sectors
[i
].is_erased
= 1;
376 cfi_command(bank
, 0xff, command
);
377 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
379 ERROR("couldn't erase block %i of flash bank at base 0x%x", i
, bank
->base
);
380 return ERROR_FLASH_OPERATION_FAILED
;
384 cfi_command(bank
, 0xff, command
);
385 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
390 int cfi_erase(struct flash_bank_s
*bank
, int first
, int last
)
392 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
394 if (cfi_info
->target
->state
!= TARGET_HALTED
)
396 return ERROR_TARGET_NOT_HALTED
;
399 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
401 return ERROR_FLASH_SECTOR_INVALID
;
404 if (cfi_info
->qry
[0] != 'Q')
405 return ERROR_FLASH_BANK_NOT_PROBED
;
407 switch(cfi_info
->pri_id
)
411 return cfi_intel_erase(bank
, first
, last
);
414 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
421 int cfi_intel_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
423 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
424 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
425 target_t
*target
= cfi_info
->target
;
429 if (!(pri_ext
->feature_support
& 0x28))
430 return ERROR_FLASH_OPERATION_FAILED
;
432 cfi_intel_clear_status_register(bank
);
434 for (i
= first
; i
<= last
; i
++)
436 cfi_command(bank
, 0x60, command
);
437 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
440 cfi_command(bank
, 0x01, command
);
441 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
442 bank
->sectors
[i
].is_protected
= 1;
446 cfi_command(bank
, 0xd0, command
);
447 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
448 bank
->sectors
[i
].is_protected
= 0;
451 cfi_intel_wait_status_busy(bank
, 100);
454 /* if the device doesn't support individual block lock bits set/clear,
455 * all blocks have been unlocked in parallel, so we set those that should be protected
457 if ((!set
) && (!(pri_ext
->feature_support
& 0x20)))
459 for (i
= 0; i
< bank
->num_sectors
; i
++)
461 cfi_intel_clear_status_register(bank
);
462 cfi_command(bank
, 0x60, command
);
463 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
464 if (bank
->sectors
[i
].is_protected
== 1)
466 cfi_command(bank
, 0x01, command
);
467 target
->type
->write_memory(target
, flash_address(bank
, i
, 0x0), bank
->bus_width
, 1, command
);
470 cfi_intel_wait_status_busy(bank
, 100);
474 cfi_command(bank
, 0xff, command
);
475 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
480 int cfi_protect(struct flash_bank_s
*bank
, int set
, int first
, int last
)
482 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
484 if (cfi_info
->target
->state
!= TARGET_HALTED
)
486 return ERROR_TARGET_NOT_HALTED
;
489 if ((first
< 0) || (last
< first
) || (last
>= bank
->num_sectors
))
491 return ERROR_FLASH_SECTOR_INVALID
;
494 if (cfi_info
->qry
[0] != 'Q')
495 return ERROR_FLASH_BANK_NOT_PROBED
;
497 switch(cfi_info
->pri_id
)
501 cfi_intel_protect(bank
, set
, first
, last
);
504 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
511 void cfi_add_byte(struct flash_bank_s
*bank
, u8
*word
, u8 byte
)
513 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
514 target_t
*target
= cfi_info
->target
;
518 if (target
->endianness
== TARGET_LITTLE_ENDIAN
)
521 for (i
= 0; i
< bank
->bus_width
- 1; i
++)
522 word
[i
] = word
[i
+ 1];
523 word
[bank
->bus_width
- 1] = byte
;
528 for (i
= bank
->bus_width
- 1; i
> 0; i
--)
529 word
[i
] = word
[i
- 1];
534 int cfi_intel_write_block(struct flash_bank_s
*bank
, u8
*buffer
, u32 address
, u32 count
)
536 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
537 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
538 target_t
*target
= cfi_info
->target
;
539 reg_param_t reg_params
[5];
540 armv4_5_algorithm_t armv4_5_info
;
541 working_area_t
*source
;
542 u32 buffer_size
= 32768;
543 u8 write_command
[CFI_MAX_BUS_WIDTH
];
547 u32 word_32_code
[] = {
548 0xe4904004, /* loop: ldr r4, [r0], #4 */
549 0xe5813000, /* str r3, [r1] */
550 0xe5814000, /* str r4, [r1] */
551 0xe5914000, /* busy ldr r4, [r1] */
552 0xe3140080, /* tst r4, #0x80 */
553 0x0afffffc, /* beq busy */
554 0xe314007f, /* tst r4, #0x7f */
555 0x1a000003, /* bne done */
556 0xe2522001, /* subs r2, r2, #1 */
557 0x0a000001, /* beq done */
558 0xe2811004, /* add r1, r1 #4 */
559 0xeafffff3, /* b loop */
560 0xeafffffe, /* done: b -2 */
563 u32 word_16_code
[] = {
564 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
565 0xe1c130b0, /* strh r3, [r1] */
566 0xe1c140b0, /* strh r4, [r1] */
567 0xe1d140b0, /* busy ldrh r4, [r1] */
568 0xe3140080, /* tst r4, #0x80 */
569 0x0afffffc, /* beq busy */
570 0xe314007f, /* tst r4, #0x7f */
571 0x1a000003, /* bne done */
572 0xe2522001, /* subs r2, r2, #1 */
573 0x0a000001, /* beq done */
574 0xe2811002, /* add r1, r1 #2 */
575 0xeafffff3, /* b loop */
576 0xeafffffe, /* done: b -2 */
579 u32 word_8_code
[] = {
580 0xe4d04001, /* loop: ldrb r4, [r0], #1 */
581 0xe5c13000, /* strb r3, [r1] */
582 0xe5c14000, /* strb r4, [r1] */
583 0xe5d14000, /* busy ldrb r4, [r1] */
584 0xe3140080, /* tst r4, #0x80 */
585 0x0afffffc, /* beq busy */
586 0xe314007f, /* tst r4, #0x7f */
587 0x1a000003, /* bne done */
588 0xe2522001, /* subs r2, r2, #1 */
589 0x0a000001, /* beq done */
590 0xe2811001, /* add r1, r1 #1 */
591 0xeafffff3, /* b loop */
592 0xeafffffe, /* done: b -2 */
595 cfi_intel_clear_status_register(bank
);
597 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
598 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
599 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
601 /* flash write code */
602 if (!cfi_info
->write_algorithm
)
604 if (target_alloc_working_area(target
, 4 * 13, &cfi_info
->write_algorithm
) != ERROR_OK
)
606 WARNING("no working area available, can't do block memory writes");
607 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
610 /* write algorithm code to working area */
611 if (bank
->bus_width
== 1)
613 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_8_code
);
615 else if (bank
->bus_width
== 2)
617 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_16_code
);
619 else if (bank
->bus_width
== 4)
621 target_write_buffer(target
, cfi_info
->write_algorithm
->address
, 13 * 4, (u8
*)word_32_code
);
625 return ERROR_FLASH_OPERATION_FAILED
;
629 while (target_alloc_working_area(target
, buffer_size
, &source
) != ERROR_OK
)
632 if (buffer_size
<= 256)
634 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
635 if (cfi_info
->write_algorithm
)
636 target_free_working_area(target
, cfi_info
->write_algorithm
);
638 WARNING("no large enough working area available, can't do block memory writes");
639 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
643 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
644 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
645 init_reg_param(®_params
[2], "r2", 32, PARAM_OUT
);
646 init_reg_param(®_params
[3], "r3", 32, PARAM_OUT
);
647 init_reg_param(®_params
[4], "r4", 32, PARAM_IN
);
651 u32 thisrun_count
= (count
> buffer_size
) ? buffer_size
: count
;
653 target_write_buffer(target
, source
->address
, thisrun_count
, buffer
);
655 buf_set_u32(reg_params
[0].value
, 0, 32, source
->address
);
656 buf_set_u32(reg_params
[1].value
, 0, 32, address
);
657 buf_set_u32(reg_params
[2].value
, 0, 32, thisrun_count
/ bank
->bus_width
);
658 cfi_command(bank
, 0x40, write_command
);
659 buf_set_u32(reg_params
[3].value
, 0, 32, buf_get_u32(write_command
, 0, 32));
661 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
)
663 cfi_intel_clear_status_register(bank
);
664 return ERROR_FLASH_OPERATION_FAILED
;
667 if (buf_get_u32(reg_params
[4].value
, 0, 32) != 0x80)
669 /* read status register (outputs debug inforation) */
670 cfi_intel_wait_status_busy(bank
, 100);
671 cfi_intel_clear_status_register(bank
);
672 return ERROR_FLASH_OPERATION_FAILED
;
675 buffer
+= thisrun_count
;
676 address
+= thisrun_count
;
677 count
-= thisrun_count
;
680 destroy_reg_param(®_params
[0]);
681 destroy_reg_param(®_params
[1]);
682 destroy_reg_param(®_params
[2]);
683 destroy_reg_param(®_params
[3]);
684 destroy_reg_param(®_params
[4]);
689 int cfi_intel_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
691 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
692 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
693 target_t
*target
= cfi_info
->target
;
696 cfi_intel_clear_status_register(bank
);
697 cfi_command(bank
, 0x40, command
);
698 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, command
);
700 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, word
);
702 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->word_write_timeout_max
)) != 0x80)
704 cfi_command(bank
, 0xff, command
);
705 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
707 ERROR("couldn't write word at base 0x%x, address %x", bank
->base
, address
);
708 return ERROR_FLASH_OPERATION_FAILED
;
714 int cfi_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
716 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
717 target_t
*target
= cfi_info
->target
;
719 switch(cfi_info
->pri_id
)
723 return cfi_intel_write_word(bank
, word
, address
);
726 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
730 return ERROR_FLASH_OPERATION_FAILED
;
733 int cfi_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
735 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
736 target_t
*target
= cfi_info
->target
;
737 u32 address
= bank
->base
+ offset
; /* address of first byte to be programmed */
739 int align
; /* number of unaligned bytes */
740 u8 current_word
[CFI_MAX_BUS_WIDTH
* 4]; /* word (bus_width size) currently being programmed */
744 if (cfi_info
->target
->state
!= TARGET_HALTED
)
746 return ERROR_TARGET_NOT_HALTED
;
749 if (offset
+ count
> bank
->size
)
750 return ERROR_FLASH_DST_OUT_OF_BANK
;
752 if (cfi_info
->qry
[0] != 'Q')
753 return ERROR_FLASH_BANK_NOT_PROBED
;
755 /* start at the first byte of the first word (bus_width size) */
756 write_p
= address
& ~(bank
->bus_width
- 1);
757 if ((align
= address
- write_p
) != 0)
759 for (i
= 0; i
< bank
->bus_width
; i
++)
763 /* copy bytes before the first write address */
764 for (i
= 0; i
< align
; ++i
, ++copy_p
)
767 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
768 cfi_add_byte(bank
, current_word
, byte
);
771 /* add bytes from the buffer */
772 for (; (i
< bank
->bus_width
) && (count
> 0); i
++)
774 cfi_add_byte(bank
, current_word
, *buffer
++);
779 /* if the buffer is already finished, copy bytes after the last write address */
780 for (; (count
== 0) && (i
< bank
->bus_width
); ++i
, ++copy_p
)
783 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
784 cfi_add_byte(bank
, current_word
, byte
);
787 retval
= cfi_write_word(bank
, current_word
, write_p
);
788 if (retval
!= ERROR_OK
)
793 /* handle blocks of bus_size aligned bytes */
794 switch(cfi_info
->pri_id
)
796 /* try block writes (fails without working area) */
799 retval
= cfi_intel_write_block(bank
, buffer
, write_p
, count
);
802 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
805 if (retval
!= ERROR_OK
)
807 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
809 /* fall back to memory writes */
810 while (count
> bank
->bus_width
)
812 for (i
= 0; i
< bank
->bus_width
; i
++)
815 for (i
= 0; i
< bank
->bus_width
; i
++)
817 cfi_add_byte(bank
, current_word
, *buffer
++);
820 retval
= cfi_write_word(bank
, current_word
, write_p
);
821 if (retval
!= ERROR_OK
)
823 write_p
+= bank
->bus_width
;
824 count
-= bank
->bus_width
;
831 /* handle unaligned tail bytes */
835 for (i
= 0; i
< bank
->bus_width
; i
++)
838 for (i
= 0; (i
< bank
->bus_width
) && (count
> 0); ++i
, ++copy_p
)
840 cfi_add_byte(bank
, current_word
, *buffer
++);
843 for (; i
< bank
->bus_width
; ++i
, ++copy_p
)
846 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
847 cfi_add_byte(bank
, current_word
, byte
);
849 retval
= cfi_write_word(bank
, current_word
, write_p
);
850 if (retval
!= ERROR_OK
)
854 /* return to read array mode */
855 cfi_command(bank
, 0xf0, current_word
);
856 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
857 cfi_command(bank
, 0xff, current_word
);
858 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
863 int cfi_probe(struct flash_bank_s
*bank
)
865 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
866 target_t
*target
= cfi_info
->target
;
870 cfi_command(bank
, 0x98, command
);
871 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
873 cfi_info
->qry
[0] = cfi_query_u8(bank
, 0, 0x10);
874 cfi_info
->qry
[1] = cfi_query_u8(bank
, 0, 0x11);
875 cfi_info
->qry
[2] = cfi_query_u8(bank
, 0, 0x12);
877 if ((cfi_info
->qry
[0] != 'Q') || (cfi_info
->qry
[1] != 'R') || (cfi_info
->qry
[2] != 'Y'))
879 cfi_command(bank
, 0xf0, command
);
880 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
881 cfi_command(bank
, 0xff, command
);
882 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
883 return ERROR_FLASH_BANK_INVALID
;
886 cfi_info
->pri_id
= cfi_query_u16(bank
, 0, 0x13);
887 cfi_info
->pri_addr
= cfi_query_u16(bank
, 0, 0x15);
888 cfi_info
->alt_id
= cfi_query_u16(bank
, 0, 0x17);
889 cfi_info
->alt_addr
= cfi_query_u16(bank
, 0, 0x19);
891 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
);
893 cfi_info
->vcc_min
= cfi_query_u8(bank
, 0, 0x1b);
894 cfi_info
->vcc_max
= cfi_query_u8(bank
, 0, 0x1c);
895 cfi_info
->vpp_min
= cfi_query_u8(bank
, 0, 0x1d);
896 cfi_info
->vpp_max
= cfi_query_u8(bank
, 0, 0x1e);
897 cfi_info
->word_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x1f);
898 cfi_info
->buf_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x20);
899 cfi_info
->block_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x21);
900 cfi_info
->chip_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x22);
901 cfi_info
->word_write_timeout_max
= cfi_query_u8(bank
, 0, 0x23);
902 cfi_info
->buf_write_timeout_max
= cfi_query_u8(bank
, 0, 0x24);
903 cfi_info
->block_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x25);
904 cfi_info
->chip_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x26);
906 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",
907 (cfi_info
->vcc_min
& 0xf0) >> 4, cfi_info
->vcc_min
& 0x0f,
908 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
909 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
910 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
911 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
,
912 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
913 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
),
914 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
915 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
916 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
918 cfi_info
->dev_size
= cfi_query_u8(bank
, 0, 0x27);
919 cfi_info
->interface_desc
= cfi_query_u16(bank
, 0, 0x28);
920 cfi_info
->max_buf_write_size
= cfi_query_u16(bank
, 0, 0x2a);
921 cfi_info
->num_erase_regions
= cfi_query_u8(bank
, 0, 0x2c);
923 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
);
925 if (1 << cfi_info
->dev_size
!= bank
->size
)
927 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank
->size
, 1 << cfi_info
->dev_size
);
930 if (cfi_info
->num_erase_regions
)
936 cfi_info
->erase_region_info
= malloc(4 * cfi_info
->num_erase_regions
);
938 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
940 cfi_info
->erase_region_info
[i
] = cfi_query_u32(bank
, 0, 0x2d + (4 * i
));
941 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);
943 num_sectors
+= (cfi_info
->erase_region_info
[i
] & 0xffff) + 1;
946 bank
->num_sectors
= num_sectors
;
947 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
948 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
951 for (j
= 0; j
< (cfi_info
->erase_region_info
[i
] & 0xffff) + 1; j
++)
953 bank
->sectors
[sector
].offset
= offset
;
954 bank
->sectors
[sector
].size
= (cfi_info
->erase_region_info
[i
] >> 16) * 256;
955 offset
+= bank
->sectors
[sector
].size
;
956 bank
->sectors
[sector
].is_erased
= -1;
957 bank
->sectors
[sector
].is_protected
= -1;
964 cfi_info
->erase_region_info
= NULL
;
967 switch(cfi_info
->pri_id
)
971 cfi_read_intel_pri_ext(bank
);
974 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
978 /* return to read array mode */
979 cfi_command(bank
, 0xf0, command
);
980 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
981 cfi_command(bank
, 0xff, command
);
982 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
987 int cfi_erase_check(struct flash_bank_s
*bank
)
989 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
990 target_t
*target
= cfi_info
->target
;
994 if (!cfi_info
->erase_check_algorithm
)
996 u32 erase_check_code
[] =
1005 /* make sure we have a working area */
1006 if (target_alloc_working_area(target
, 20, &cfi_info
->erase_check_algorithm
) != ERROR_OK
)
1008 WARNING("no working area available, falling back to slow memory reads");
1012 /* write algorithm code to working area */
1013 target
->type
->write_memory(target
, cfi_info
->erase_check_algorithm
->address
, 4, 5, (u8
*)erase_check_code
);
1017 if (!cfi_info
->erase_check_algorithm
)
1019 u32
*buffer
= malloc(4096);
1021 for (i
= 0; i
< bank
->num_sectors
; i
++)
1023 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1024 u32 size
= bank
->sectors
[i
].size
;
1025 u32 check
= 0xffffffffU
;
1030 u32 thisrun_size
= (size
> 4096) ? 4096 : size
;
1033 target
->type
->read_memory(target
, address
, 4, thisrun_size
/ 4, (u8
*)buffer
);
1035 for (j
= 0; j
< thisrun_size
/ 4; j
++)
1038 if (check
!= 0xffffffff)
1044 size
-= thisrun_size
;
1045 address
+= thisrun_size
;
1048 bank
->sectors
[i
].is_erased
= erased
;
1055 for (i
= 0; i
< bank
->num_sectors
; i
++)
1057 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1058 u32 size
= bank
->sectors
[i
].size
;
1060 reg_param_t reg_params
[3];
1061 armv4_5_algorithm_t armv4_5_info
;
1063 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
1064 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
1065 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
1067 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
1068 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
1070 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
1071 buf_set_u32(reg_params
[1].value
, 0, 32, size
);
1073 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
1074 buf_set_u32(reg_params
[2].value
, 0, 32, 0xff);
1076 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
)
1077 return ERROR_FLASH_OPERATION_FAILED
;
1079 if (buf_get_u32(reg_params
[2].value
, 0, 32) == 0xff)
1080 bank
->sectors
[i
].is_erased
= 1;
1082 bank
->sectors
[i
].is_erased
= 0;
1084 destroy_reg_param(®_params
[0]);
1085 destroy_reg_param(®_params
[1]);
1086 destroy_reg_param(®_params
[2]);
1093 int cfi_intel_protect_check(struct flash_bank_s
*bank
)
1095 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1096 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
1097 target_t
*target
= cfi_info
->target
;
1101 /* check if block lock bits are supported on this device */
1102 if (!(pri_ext
->blk_status_reg_mask
& 0x1))
1103 return ERROR_FLASH_OPERATION_FAILED
;
1105 cfi_command(bank
, 0x90, command
);
1106 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
1108 for (i
= 0; i
< bank
->num_sectors
; i
++)
1110 u8 block_status
= cfi_get_u8(bank
, i
, 0x2);
1112 if (block_status
& 1)
1113 bank
->sectors
[i
].is_protected
= 1;
1115 bank
->sectors
[i
].is_protected
= 0;
1118 cfi_command(bank
, 0xff, command
);
1119 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
1124 int cfi_protect_check(struct flash_bank_s
*bank
)
1126 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1127 target_t
*target
= cfi_info
->target
;
1129 if (cfi_info
->qry
[0] != 'Q')
1130 return ERROR_FLASH_BANK_NOT_PROBED
;
1132 switch(cfi_info
->pri_id
)
1136 return cfi_intel_protect_check(bank
);
1139 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
1146 int cfi_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
1149 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1151 if (cfi_info
->qry
[0] == -1)
1153 printed
= snprintf(buf
, buf_size
, "\ncfi flash bank not probed yet\n");
1157 printed
= snprintf(buf
, buf_size
, "\ncfi information:\n");
1159 buf_size
-= printed
;
1161 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
);
1163 buf_size
-= printed
;
1165 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,
1166 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
1167 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
1168 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
1170 buf_size
-= printed
;
1172 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
,
1173 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
1175 buf_size
-= printed
;
1177 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
),
1178 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
1179 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
1180 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
1182 buf_size
-= printed
;
1184 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
);
1186 buf_size
-= printed
;
1188 switch(cfi_info
->pri_id
)
1192 cfi_intel_info(bank
, buf
, buf_size
);
1195 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)