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 target_free_working_area(target
, source
);
690 destroy_reg_param(®_params
[0]);
691 destroy_reg_param(®_params
[1]);
692 destroy_reg_param(®_params
[2]);
693 destroy_reg_param(®_params
[3]);
694 destroy_reg_param(®_params
[4]);
699 int cfi_intel_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
701 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
702 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
703 target_t
*target
= cfi_info
->target
;
706 cfi_intel_clear_status_register(bank
);
707 cfi_command(bank
, 0x40, command
);
708 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, command
);
710 target
->type
->write_memory(target
, address
, bank
->bus_width
, 1, word
);
712 if (cfi_intel_wait_status_busy(bank
, 1000 * (1 << cfi_info
->word_write_timeout_max
)) != 0x80)
714 cfi_command(bank
, 0xff, command
);
715 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
717 ERROR("couldn't write word at base 0x%x, address %x", bank
->base
, address
);
718 return ERROR_FLASH_OPERATION_FAILED
;
724 int cfi_write_word(struct flash_bank_s
*bank
, u8
*word
, u32 address
)
726 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
727 target_t
*target
= cfi_info
->target
;
729 switch(cfi_info
->pri_id
)
733 return cfi_intel_write_word(bank
, word
, address
);
736 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
740 return ERROR_FLASH_OPERATION_FAILED
;
743 int cfi_write(struct flash_bank_s
*bank
, u8
*buffer
, u32 offset
, u32 count
)
745 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
746 target_t
*target
= cfi_info
->target
;
747 u32 address
= bank
->base
+ offset
; /* address of first byte to be programmed */
749 int align
; /* number of unaligned bytes */
750 u8 current_word
[CFI_MAX_BUS_WIDTH
* 4]; /* word (bus_width size) currently being programmed */
754 if (cfi_info
->target
->state
!= TARGET_HALTED
)
756 return ERROR_TARGET_NOT_HALTED
;
759 if (offset
+ count
> bank
->size
)
760 return ERROR_FLASH_DST_OUT_OF_BANK
;
762 if (cfi_info
->qry
[0] != 'Q')
763 return ERROR_FLASH_BANK_NOT_PROBED
;
765 /* start at the first byte of the first word (bus_width size) */
766 write_p
= address
& ~(bank
->bus_width
- 1);
767 if ((align
= address
- write_p
) != 0)
769 for (i
= 0; i
< bank
->bus_width
; i
++)
773 /* copy bytes before the first write address */
774 for (i
= 0; i
< align
; ++i
, ++copy_p
)
777 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
778 cfi_add_byte(bank
, current_word
, byte
);
781 /* add bytes from the buffer */
782 for (; (i
< bank
->bus_width
) && (count
> 0); i
++)
784 cfi_add_byte(bank
, current_word
, *buffer
++);
789 /* if the buffer is already finished, copy bytes after the last write address */
790 for (; (count
== 0) && (i
< bank
->bus_width
); ++i
, ++copy_p
)
793 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
794 cfi_add_byte(bank
, current_word
, byte
);
797 retval
= cfi_write_word(bank
, current_word
, write_p
);
798 if (retval
!= ERROR_OK
)
803 /* handle blocks of bus_size aligned bytes */
804 switch(cfi_info
->pri_id
)
806 /* try block writes (fails without working area) */
809 retval
= cfi_intel_write_block(bank
, buffer
, write_p
, count
);
812 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
815 if (retval
!= ERROR_OK
)
817 if (retval
== ERROR_TARGET_RESOURCE_NOT_AVAILABLE
)
819 /* fall back to memory writes */
820 while (count
> bank
->bus_width
)
822 for (i
= 0; i
< bank
->bus_width
; i
++)
825 for (i
= 0; i
< bank
->bus_width
; i
++)
827 cfi_add_byte(bank
, current_word
, *buffer
++);
830 retval
= cfi_write_word(bank
, current_word
, write_p
);
831 if (retval
!= ERROR_OK
)
833 write_p
+= bank
->bus_width
;
834 count
-= bank
->bus_width
;
841 /* handle unaligned tail bytes */
845 for (i
= 0; i
< bank
->bus_width
; i
++)
848 for (i
= 0; (i
< bank
->bus_width
) && (count
> 0); ++i
, ++copy_p
)
850 cfi_add_byte(bank
, current_word
, *buffer
++);
853 for (; i
< bank
->bus_width
; ++i
, ++copy_p
)
856 target
->type
->read_memory(target
, copy_p
, 1, 1, &byte
);
857 cfi_add_byte(bank
, current_word
, byte
);
859 retval
= cfi_write_word(bank
, current_word
, write_p
);
860 if (retval
!= ERROR_OK
)
864 /* return to read array mode */
865 cfi_command(bank
, 0xf0, current_word
);
866 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
867 cfi_command(bank
, 0xff, current_word
);
868 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, current_word
);
873 int cfi_probe(struct flash_bank_s
*bank
)
875 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
876 target_t
*target
= cfi_info
->target
;
880 cfi_command(bank
, 0x98, command
);
881 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
883 cfi_info
->qry
[0] = cfi_query_u8(bank
, 0, 0x10);
884 cfi_info
->qry
[1] = cfi_query_u8(bank
, 0, 0x11);
885 cfi_info
->qry
[2] = cfi_query_u8(bank
, 0, 0x12);
887 DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info
->qry
[0], cfi_info
->qry
[1], cfi_info
->qry
[2]);
889 if ((cfi_info
->qry
[0] != 'Q') || (cfi_info
->qry
[1] != 'R') || (cfi_info
->qry
[2] != 'Y'))
891 cfi_command(bank
, 0xf0, command
);
892 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
893 cfi_command(bank
, 0xff, command
);
894 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
895 return ERROR_FLASH_BANK_INVALID
;
898 cfi_info
->pri_id
= cfi_query_u16(bank
, 0, 0x13);
899 cfi_info
->pri_addr
= cfi_query_u16(bank
, 0, 0x15);
900 cfi_info
->alt_id
= cfi_query_u16(bank
, 0, 0x17);
901 cfi_info
->alt_addr
= cfi_query_u16(bank
, 0, 0x19);
903 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
);
905 cfi_info
->vcc_min
= cfi_query_u8(bank
, 0, 0x1b);
906 cfi_info
->vcc_max
= cfi_query_u8(bank
, 0, 0x1c);
907 cfi_info
->vpp_min
= cfi_query_u8(bank
, 0, 0x1d);
908 cfi_info
->vpp_max
= cfi_query_u8(bank
, 0, 0x1e);
909 cfi_info
->word_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x1f);
910 cfi_info
->buf_write_timeout_typ
= cfi_query_u8(bank
, 0, 0x20);
911 cfi_info
->block_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x21);
912 cfi_info
->chip_erase_timeout_typ
= cfi_query_u8(bank
, 0, 0x22);
913 cfi_info
->word_write_timeout_max
= cfi_query_u8(bank
, 0, 0x23);
914 cfi_info
->buf_write_timeout_max
= cfi_query_u8(bank
, 0, 0x24);
915 cfi_info
->block_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x25);
916 cfi_info
->chip_erase_timeout_max
= cfi_query_u8(bank
, 0, 0x26);
918 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",
919 (cfi_info
->vcc_min
& 0xf0) >> 4, cfi_info
->vcc_min
& 0x0f,
920 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
921 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
922 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
923 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
,
924 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
925 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
),
926 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
927 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
928 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
930 cfi_info
->dev_size
= cfi_query_u8(bank
, 0, 0x27);
931 cfi_info
->interface_desc
= cfi_query_u16(bank
, 0, 0x28);
932 cfi_info
->max_buf_write_size
= cfi_query_u16(bank
, 0, 0x2a);
933 cfi_info
->num_erase_regions
= cfi_query_u8(bank
, 0, 0x2c);
935 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
);
937 if (1 << cfi_info
->dev_size
!= bank
->size
)
939 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank
->size
, 1 << cfi_info
->dev_size
);
942 if (cfi_info
->num_erase_regions
)
948 cfi_info
->erase_region_info
= malloc(4 * cfi_info
->num_erase_regions
);
950 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
952 cfi_info
->erase_region_info
[i
] = cfi_query_u32(bank
, 0, 0x2d + (4 * i
));
953 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);
955 num_sectors
+= (cfi_info
->erase_region_info
[i
] & 0xffff) + 1;
958 bank
->num_sectors
= num_sectors
;
959 bank
->sectors
= malloc(sizeof(flash_sector_t
) * num_sectors
);
960 for (i
= 0; i
< cfi_info
->num_erase_regions
; i
++)
963 for (j
= 0; j
< (cfi_info
->erase_region_info
[i
] & 0xffff) + 1; j
++)
965 bank
->sectors
[sector
].offset
= offset
;
966 bank
->sectors
[sector
].size
= (cfi_info
->erase_region_info
[i
] >> 16) * 256;
967 offset
+= bank
->sectors
[sector
].size
;
968 bank
->sectors
[sector
].is_erased
= -1;
969 bank
->sectors
[sector
].is_protected
= -1;
976 cfi_info
->erase_region_info
= NULL
;
979 switch(cfi_info
->pri_id
)
983 cfi_read_intel_pri_ext(bank
);
986 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
990 /* return to read array mode */
991 cfi_command(bank
, 0xf0, command
);
992 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
993 cfi_command(bank
, 0xff, command
);
994 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
999 int cfi_erase_check(struct flash_bank_s
*bank
)
1001 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1002 target_t
*target
= cfi_info
->target
;
1006 if (!cfi_info
->erase_check_algorithm
)
1008 u32 erase_check_code
[] =
1010 0xe4d03001, /* ldrb r3, [r0], #1 */
1011 0xe0022003, /* and r2, r2, r3 */
1012 0xe2511001, /* subs r1, r1, #1 */
1013 0x1afffffb, /* b -4 */
1014 0xeafffffe /* b 0 */
1017 /* make sure we have a working area */
1018 if (target_alloc_working_area(target
, 20, &cfi_info
->erase_check_algorithm
) != ERROR_OK
)
1020 WARNING("no working area available, falling back to slow memory reads");
1024 u8 erase_check_code_buf
[5 * 4];
1026 for (i
= 0; i
< 5; i
++)
1027 target_buffer_set_u32(target
, erase_check_code_buf
+ (i
*4), erase_check_code
[i
]);
1029 /* write algorithm code to working area */
1030 target
->type
->write_memory(target
, cfi_info
->erase_check_algorithm
->address
, 4, 5, erase_check_code_buf
);
1034 if (!cfi_info
->erase_check_algorithm
)
1036 u32
*buffer
= malloc(4096);
1038 for (i
= 0; i
< bank
->num_sectors
; i
++)
1040 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1041 u32 size
= bank
->sectors
[i
].size
;
1042 u32 check
= 0xffffffffU
;
1047 u32 thisrun_size
= (size
> 4096) ? 4096 : size
;
1050 target
->type
->read_memory(target
, address
, 4, thisrun_size
/ 4, (u8
*)buffer
);
1052 for (j
= 0; j
< thisrun_size
/ 4; j
++)
1055 if (check
!= 0xffffffff)
1061 size
-= thisrun_size
;
1062 address
+= thisrun_size
;
1065 bank
->sectors
[i
].is_erased
= erased
;
1072 for (i
= 0; i
< bank
->num_sectors
; i
++)
1074 u32 address
= bank
->base
+ bank
->sectors
[i
].offset
;
1075 u32 size
= bank
->sectors
[i
].size
;
1077 reg_param_t reg_params
[3];
1078 armv4_5_algorithm_t armv4_5_info
;
1080 armv4_5_info
.common_magic
= ARMV4_5_COMMON_MAGIC
;
1081 armv4_5_info
.core_mode
= ARMV4_5_MODE_SVC
;
1082 armv4_5_info
.core_state
= ARMV4_5_STATE_ARM
;
1084 init_reg_param(®_params
[0], "r0", 32, PARAM_OUT
);
1085 buf_set_u32(reg_params
[0].value
, 0, 32, address
);
1087 init_reg_param(®_params
[1], "r1", 32, PARAM_OUT
);
1088 buf_set_u32(reg_params
[1].value
, 0, 32, size
);
1090 init_reg_param(®_params
[2], "r2", 32, PARAM_IN_OUT
);
1091 buf_set_u32(reg_params
[2].value
, 0, 32, 0xff);
1093 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
)
1094 return ERROR_FLASH_OPERATION_FAILED
;
1096 if (buf_get_u32(reg_params
[2].value
, 0, 32) == 0xff)
1097 bank
->sectors
[i
].is_erased
= 1;
1099 bank
->sectors
[i
].is_erased
= 0;
1101 destroy_reg_param(®_params
[0]);
1102 destroy_reg_param(®_params
[1]);
1103 destroy_reg_param(®_params
[2]);
1110 int cfi_intel_protect_check(struct flash_bank_s
*bank
)
1112 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1113 cfi_intel_pri_ext_t
*pri_ext
= cfi_info
->pri_ext
;
1114 target_t
*target
= cfi_info
->target
;
1118 /* check if block lock bits are supported on this device */
1119 if (!(pri_ext
->blk_status_reg_mask
& 0x1))
1120 return ERROR_FLASH_OPERATION_FAILED
;
1122 cfi_command(bank
, 0x90, command
);
1123 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x55), bank
->bus_width
, 1, command
);
1125 for (i
= 0; i
< bank
->num_sectors
; i
++)
1127 u8 block_status
= cfi_get_u8(bank
, i
, 0x2);
1129 if (block_status
& 1)
1130 bank
->sectors
[i
].is_protected
= 1;
1132 bank
->sectors
[i
].is_protected
= 0;
1135 cfi_command(bank
, 0xff, command
);
1136 target
->type
->write_memory(target
, flash_address(bank
, 0, 0x0), bank
->bus_width
, 1, command
);
1141 int cfi_protect_check(struct flash_bank_s
*bank
)
1143 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1144 target_t
*target
= cfi_info
->target
;
1146 if (cfi_info
->qry
[0] != 'Q')
1147 return ERROR_FLASH_BANK_NOT_PROBED
;
1149 switch(cfi_info
->pri_id
)
1153 return cfi_intel_protect_check(bank
);
1156 ERROR("cfi primary command set %i unsupported", cfi_info
->pri_id
);
1163 int cfi_info(struct flash_bank_s
*bank
, char *buf
, int buf_size
)
1166 cfi_flash_bank_t
*cfi_info
= bank
->driver_priv
;
1168 if (cfi_info
->qry
[0] == -1)
1170 printed
= snprintf(buf
, buf_size
, "\ncfi flash bank not probed yet\n");
1174 printed
= snprintf(buf
, buf_size
, "\ncfi information:\n");
1176 buf_size
-= printed
;
1178 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
);
1180 buf_size
-= printed
;
1182 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,
1183 (cfi_info
->vcc_max
& 0xf0) >> 4, cfi_info
->vcc_max
& 0x0f,
1184 (cfi_info
->vpp_min
& 0xf0) >> 4, cfi_info
->vpp_min
& 0x0f,
1185 (cfi_info
->vpp_max
& 0xf0) >> 4, cfi_info
->vpp_max
& 0x0f);
1187 buf_size
-= printed
;
1189 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
,
1190 1 << cfi_info
->block_erase_timeout_typ
, 1 << cfi_info
->chip_erase_timeout_typ
);
1192 buf_size
-= printed
;
1194 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
),
1195 (1 << cfi_info
->buf_write_timeout_max
) * (1 << cfi_info
->buf_write_timeout_typ
),
1196 (1 << cfi_info
->block_erase_timeout_max
) * (1 << cfi_info
->block_erase_timeout_typ
),
1197 (1 << cfi_info
->chip_erase_timeout_max
) * (1 << cfi_info
->chip_erase_timeout_typ
));
1199 buf_size
-= printed
;
1201 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
);
1203 buf_size
-= printed
;
1205 switch(cfi_info
->pri_id
)
1209 cfi_intel_info(bank
, buf
, buf_size
);
1212 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)