- Added support for native MinGW builds (thanks to Spencer Oliver and Michael Fischer...
[openocd.git] / src / flash / cfi.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "replacements.h"
25
26 #include "cfi.h"
27
28 #include "flash.h"
29 #include "target.h"
30 #include "log.h"
31 #include "armv4_5.h"
32 #include "algorithm.h"
33 #include "binarybuffer.h"
34 #include "types.h"
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
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);
49
50 int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
51
52 #define CFI_MAX_BUS_WIDTH 4
53
54 flash_driver_t cfi_flash =
55 {
56 .name = "cfi",
57 .register_commands = cfi_register_commands,
58 .flash_bank_command = cfi_flash_bank_command,
59 .erase = cfi_erase,
60 .protect = cfi_protect,
61 .write = cfi_write,
62 .probe = cfi_probe,
63 .erase_check = cfi_erase_check,
64 .protect_check = cfi_protect_check,
65 .info = cfi_info
66 };
67
68 inline u32 flash_address(flash_bank_t *bank, int sector, u32 offset)
69 {
70 /* while the sector list isn't built, only accesses to sector 0 work */
71 if (sector == 0)
72 return bank->base + offset * bank->bus_width;
73 else
74 {
75 if (!bank->sectors)
76 {
77 ERROR("BUG: sector list not yet built");
78 exit(-1);
79 }
80 return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
81 }
82
83 }
84
85 void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
86 {
87 cfi_flash_bank_t *cfi_info = bank->driver_priv;
88 int i;
89
90 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
91 {
92 for (i = bank->bus_width; i > 0; i--)
93 {
94 *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
95 }
96 }
97 else
98 {
99 for (i = 1; i <= bank->bus_width; i++)
100 {
101 *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
102 }
103 }
104 }
105
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
109 */
110 u8 cfi_query_u8(flash_bank_t *bank, int sector, u32 offset)
111 {
112 cfi_flash_bank_t *cfi_info = bank->driver_priv;
113 target_t *target = cfi_info->target;
114 u8 data[CFI_MAX_BUS_WIDTH];
115
116 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
117
118 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
119 return data[0];
120 else
121 return data[bank->bus_width - 1];
122 }
123
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
127 */
128 u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset)
129 {
130 cfi_flash_bank_t *cfi_info = bank->driver_priv;
131 target_t *target = cfi_info->target;
132 u8 data[CFI_MAX_BUS_WIDTH];
133 int i;
134
135 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
136
137 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
138 {
139 for (i = 0; i < bank->bus_width / bank->chip_width; i++)
140 data[0] |= data[i];
141
142 return data[0];
143 }
144 else
145 {
146 u8 value = 0;
147 for (i = 0; i < bank->bus_width / bank->chip_width; i++)
148 value |= data[bank->bus_width - 1 - i];
149
150 return value;
151 }
152 }
153
154 u16 cfi_query_u16(flash_bank_t *bank, int sector, u32 offset)
155 {
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];
159
160 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
161
162 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
163 return data[0] | data[bank->bus_width] << 8;
164 else
165 return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
166 }
167
168 u32 cfi_query_u32(flash_bank_t *bank, int sector, u32 offset)
169 {
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];
173
174 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
175
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;
178 else
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;
181 }
182
183 void cfi_intel_clear_status_register(flash_bank_t *bank)
184 {
185 cfi_flash_bank_t *cfi_info = bank->driver_priv;
186 target_t *target = cfi_info->target;
187 u8 command[8];
188
189 if (target->state != TARGET_HALTED)
190 {
191 ERROR("BUG: attempted to clear status register while target wasn't halted");
192 exit(-1);
193 }
194
195 cfi_command(bank, 0x50, command);
196 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
197 }
198
199 u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
200 {
201 u8 status;
202
203 while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0))
204 {
205 DEBUG("status: 0x%x", status);
206 usleep(1000);
207 }
208
209 DEBUG("status: 0x%x", status);
210
211 if (status != 0x80)
212 {
213 ERROR("status register: 0x%x", status);
214 if (status & 0x2)
215 ERROR("Block Lock-Bit Detected, Operation Abort");
216 if (status & 0x4)
217 ERROR("Program suspended");
218 if (status & 0x8)
219 ERROR("Low Programming Voltage Detected, Operation Aborted");
220 if (status & 0x10)
221 ERROR("Program Error / Error in Setting Lock-Bit");
222 if (status & 0x20)
223 ERROR("Error in Block Erasure or Clear Lock-Bits");
224 if (status & 0x40)
225 ERROR("Block Erase Suspended");
226
227 cfi_intel_clear_status_register(bank);
228 }
229
230 return status;
231 }
232 int cfi_read_intel_pri_ext(flash_bank_t *bank)
233 {
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;
237 u8 command[8];
238
239 cfi_info->pri_ext = pri_ext;
240
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);
244
245 if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
246 {
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;
252 }
253
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);
256
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);
258
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);
262
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);
264
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);
267
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);
271
272 pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe);
273 if (pri_ext->num_protection_fields != 1)
274 {
275 WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields);
276 }
277
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);
281
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);
283
284 return ERROR_OK;
285 }
286
287 int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
288 {
289 int printed;
290 cfi_flash_bank_t *cfi_info = bank->driver_priv;
291 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
292
293 printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
294 buf += printed;
295 buf_size -= printed;
296
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);
298 buf += printed;
299 buf_size -= printed;
300
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);
302 buf += printed;
303 buf_size -= printed;
304
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);
308 buf += printed;
309 buf_size -= printed;
310
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);
312
313 return ERROR_OK;
314 }
315
316 int cfi_register_commands(struct command_context_s *cmd_ctx)
317 {
318 command_t *cfi_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
319 /*
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>");
322 */
323 return ERROR_OK;
324 }
325
326 /* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#>
327 */
328 int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
329 {
330 cfi_flash_bank_t *cfi_info;
331
332 if (argc < 6)
333 {
334 WARNING("incomplete flash_bank cfi configuration");
335 return ERROR_FLASH_BANK_INVALID;
336 }
337
338 cfi_info = malloc(sizeof(cfi_flash_bank_t));
339 bank->driver_priv = cfi_info;
340
341 cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
342 if (!cfi_info->target)
343 {
344 ERROR("no target '%i' configured", args[5]);
345 exit(-1);
346 }
347
348 /* bank wasn't probed yet */
349 cfi_info->qry[0] = -1;
350
351 return ERROR_OK;
352 }
353
354 int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
355 {
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;
359 u8 command[8];
360 int i;
361
362 cfi_intel_clear_status_register(bank);
363
364 for (i = first; i <= last; i++)
365 {
366 cfi_command(bank, 0x20, command);
367 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
368
369 cfi_command(bank, 0xd0, command);
370 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
371
372 if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80)
373 bank->sectors[i].is_erased = 1;
374 else
375 {
376 cfi_command(bank, 0xff, command);
377 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
378
379 ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base);
380 return ERROR_FLASH_OPERATION_FAILED;
381 }
382 }
383
384 cfi_command(bank, 0xff, command);
385 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
386
387 return ERROR_OK;
388 }
389
390 int cfi_erase(struct flash_bank_s *bank, int first, int last)
391 {
392 cfi_flash_bank_t *cfi_info = bank->driver_priv;
393
394 if (cfi_info->target->state != TARGET_HALTED)
395 {
396 return ERROR_TARGET_NOT_HALTED;
397 }
398
399 if ((first < 0) || (last < first) || (last >= bank->num_sectors))
400 {
401 return ERROR_FLASH_SECTOR_INVALID;
402 }
403
404 if (cfi_info->qry[0] != 'Q')
405 return ERROR_FLASH_BANK_NOT_PROBED;
406
407 switch(cfi_info->pri_id)
408 {
409 case 1:
410 case 3:
411 return cfi_intel_erase(bank, first, last);
412 break;
413 default:
414 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
415 break;
416 }
417
418 return ERROR_OK;
419 }
420
421 int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
422 {
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;
426 u8 command[8];
427 int i;
428
429 if (!(pri_ext->feature_support & 0x28))
430 return ERROR_FLASH_OPERATION_FAILED;
431
432 cfi_intel_clear_status_register(bank);
433
434 for (i = first; i <= last; i++)
435 {
436 cfi_command(bank, 0x60, command);
437 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
438 if (set)
439 {
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;
443 }
444 else
445 {
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;
449 }
450
451 cfi_intel_wait_status_busy(bank, 100);
452 }
453
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
456 */
457 if ((!set) && (!(pri_ext->feature_support & 0x20)))
458 {
459 for (i = 0; i < bank->num_sectors; i++)
460 {
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)
465 {
466 cfi_command(bank, 0x01, command);
467 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
468 }
469
470 cfi_intel_wait_status_busy(bank, 100);
471 }
472 }
473
474 cfi_command(bank, 0xff, command);
475 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
476
477 return ERROR_OK;
478 }
479
480 int cfi_protect(struct flash_bank_s *bank, int set, int first, int last)
481 {
482 cfi_flash_bank_t *cfi_info = bank->driver_priv;
483
484 if (cfi_info->target->state != TARGET_HALTED)
485 {
486 return ERROR_TARGET_NOT_HALTED;
487 }
488
489 if ((first < 0) || (last < first) || (last >= bank->num_sectors))
490 {
491 return ERROR_FLASH_SECTOR_INVALID;
492 }
493
494 if (cfi_info->qry[0] != 'Q')
495 return ERROR_FLASH_BANK_NOT_PROBED;
496
497 switch(cfi_info->pri_id)
498 {
499 case 1:
500 case 3:
501 cfi_intel_protect(bank, set, first, last);
502 break;
503 default:
504 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
505 break;
506 }
507
508 return ERROR_OK;
509 }
510
511 void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte)
512 {
513 cfi_flash_bank_t *cfi_info = bank->driver_priv;
514 target_t *target = cfi_info->target;
515
516 int i;
517
518 if (target->endianness == TARGET_LITTLE_ENDIAN)
519 {
520 /* shift bytes */
521 for (i = 0; i < bank->bus_width - 1; i++)
522 word[i] = word[i + 1];
523 word[bank->bus_width - 1] = byte;
524 }
525 else
526 {
527 /* shift bytes */
528 for (i = bank->bus_width - 1; i > 0; i--)
529 word[i] = word[i - 1];
530 word[0] = byte;
531 }
532 }
533
534 int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count)
535 {
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];
544 int i;
545 int retval;
546
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 */
561 };
562
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 */
577 };
578
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 */
593 };
594
595 cfi_intel_clear_status_register(bank);
596
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;
600
601 /* flash write code */
602 if (!cfi_info->write_algorithm)
603 {
604 if (target_alloc_working_area(target, 4 * 13, &cfi_info->write_algorithm) != ERROR_OK)
605 {
606 WARNING("no working area available, can't do block memory writes");
607 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
608 };
609
610 /* write algorithm code to working area */
611 if (bank->bus_width == 1)
612 {
613 target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_8_code);
614 }
615 else if (bank->bus_width == 2)
616 {
617 target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_16_code);
618 }
619 else if (bank->bus_width == 4)
620 {
621 target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_32_code);
622 }
623 else
624 {
625 return ERROR_FLASH_OPERATION_FAILED;
626 }
627 }
628
629 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
630 {
631 buffer_size /= 2;
632 if (buffer_size <= 256)
633 {
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);
637
638 WARNING("no large enough working area available, can't do block memory writes");
639 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
640 }
641 };
642
643 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
644 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
645 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
646 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
647 init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
648
649 while (count > 0)
650 {
651 u32 thisrun_count = (count > buffer_size) ? buffer_size : count;
652
653 target_write_buffer(target, source->address, thisrun_count, buffer);
654
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));
660
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)
662 {
663 cfi_intel_clear_status_register(bank);
664 return ERROR_FLASH_OPERATION_FAILED;
665 }
666
667 if (buf_get_u32(reg_params[4].value, 0, 32) != 0x80)
668 {
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;
673 }
674
675 buffer += thisrun_count;
676 address += thisrun_count;
677 count -= thisrun_count;
678 }
679
680 destroy_reg_param(&reg_params[0]);
681 destroy_reg_param(&reg_params[1]);
682 destroy_reg_param(&reg_params[2]);
683 destroy_reg_param(&reg_params[3]);
684 destroy_reg_param(&reg_params[4]);
685
686 return ERROR_OK;
687 }
688
689 int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
690 {
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;
694 u8 command[8];
695
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);
699
700 target->type->write_memory(target, address, bank->bus_width, 1, word);
701
702 if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
703 {
704 cfi_command(bank, 0xff, command);
705 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
706
707 ERROR("couldn't write word at base 0x%x, address %x", bank->base, address);
708 return ERROR_FLASH_OPERATION_FAILED;
709 }
710
711 return ERROR_OK;
712 }
713
714 int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
715 {
716 cfi_flash_bank_t *cfi_info = bank->driver_priv;
717 target_t *target = cfi_info->target;
718
719 switch(cfi_info->pri_id)
720 {
721 case 1:
722 case 3:
723 return cfi_intel_write_word(bank, word, address);
724 break;
725 default:
726 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
727 break;
728 }
729
730 return ERROR_FLASH_OPERATION_FAILED;
731 }
732
733 int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
734 {
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 */
738 u32 write_p, copy_p;
739 int align; /* number of unaligned bytes */
740 u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */
741 int i;
742 int retval;
743
744 if (cfi_info->target->state != TARGET_HALTED)
745 {
746 return ERROR_TARGET_NOT_HALTED;
747 }
748
749 if (offset + count > bank->size)
750 return ERROR_FLASH_DST_OUT_OF_BANK;
751
752 if (cfi_info->qry[0] != 'Q')
753 return ERROR_FLASH_BANK_NOT_PROBED;
754
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)
758 {
759 for (i = 0; i < bank->bus_width; i++)
760 current_word[i] = 0;
761 copy_p = write_p;
762
763 /* copy bytes before the first write address */
764 for (i = 0; i < align; ++i, ++copy_p)
765 {
766 u8 byte;
767 target->type->read_memory(target, copy_p, 1, 1, &byte);
768 cfi_add_byte(bank, current_word, byte);
769 }
770
771 /* add bytes from the buffer */
772 for (; (i < bank->bus_width) && (count > 0); i++)
773 {
774 cfi_add_byte(bank, current_word, *buffer++);
775 count--;
776 copy_p++;
777 }
778
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)
781 {
782 u8 byte;
783 target->type->read_memory(target, copy_p, 1, 1, &byte);
784 cfi_add_byte(bank, current_word, byte);
785 }
786
787 retval = cfi_write_word(bank, current_word, write_p);
788 if (retval != ERROR_OK)
789 return retval;
790 write_p = copy_p;
791 }
792
793 /* handle blocks of bus_size aligned bytes */
794 switch(cfi_info->pri_id)
795 {
796 /* try block writes (fails without working area) */
797 case 1:
798 case 3:
799 retval = cfi_intel_write_block(bank, buffer, write_p, count);
800 break;
801 default:
802 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
803 break;
804 }
805 if (retval != ERROR_OK)
806 {
807 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
808 {
809 /* fall back to memory writes */
810 while (count > bank->bus_width)
811 {
812 for (i = 0; i < bank->bus_width; i++)
813 current_word[i] = 0;
814
815 for (i = 0; i < bank->bus_width; i++)
816 {
817 cfi_add_byte(bank, current_word, *buffer++);
818 }
819
820 retval = cfi_write_word(bank, current_word, write_p);
821 if (retval != ERROR_OK)
822 return retval;
823 write_p += bank->bus_width;
824 count -= bank->bus_width;
825 }
826 }
827 else
828 return retval;
829 }
830
831 /* handle unaligned tail bytes */
832 if (count > 0)
833 {
834 copy_p = write_p;
835 for (i = 0; i < bank->bus_width; i++)
836 current_word[i] = 0;
837
838 for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
839 {
840 cfi_add_byte(bank, current_word, *buffer++);
841 count--;
842 }
843 for (; i < bank->bus_width; ++i, ++copy_p)
844 {
845 u8 byte;
846 target->type->read_memory(target, copy_p, 1, 1, &byte);
847 cfi_add_byte(bank, current_word, byte);
848 }
849 retval = cfi_write_word(bank, current_word, write_p);
850 if (retval != ERROR_OK)
851 return retval;
852 }
853
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);
859
860 return ERROR_OK;
861 }
862
863 int cfi_probe(struct flash_bank_s *bank)
864 {
865 cfi_flash_bank_t *cfi_info = bank->driver_priv;
866 target_t *target = cfi_info->target;
867 u8 command[8];
868
869
870 cfi_command(bank, 0x98, command);
871 target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
872
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);
876
877 if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
878 {
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;
884 }
885
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);
890
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);
892
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);
905
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));
917
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);
922
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);
924
925 if (1 << cfi_info->dev_size != bank->size)
926 {
927 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
928 }
929
930 if (cfi_info->num_erase_regions)
931 {
932 int i;
933 int num_sectors = 0;
934 int sector = 0;
935 u32 offset = 0;
936 cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
937
938 for (i = 0; i < cfi_info->num_erase_regions; i++)
939 {
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);
942
943 num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
944 }
945
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++)
949 {
950 int j;
951 for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
952 {
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;
958 sector++;
959 }
960 }
961 }
962 else
963 {
964 cfi_info->erase_region_info = NULL;
965 }
966
967 switch(cfi_info->pri_id)
968 {
969 case 1:
970 case 3:
971 cfi_read_intel_pri_ext(bank);
972 break;
973 default:
974 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
975 break;
976 }
977
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);
983
984 return ERROR_OK;
985 }
986
987 int cfi_erase_check(struct flash_bank_s *bank)
988 {
989 cfi_flash_bank_t *cfi_info = bank->driver_priv;
990 target_t *target = cfi_info->target;
991 int i;
992 int retval;
993
994 if (!cfi_info->erase_check_algorithm)
995 {
996 u32 erase_check_code[] =
997 {
998 0xe4d03001,
999 0xe0022003,
1000 0xe2511001,
1001 0x1afffffb,
1002 0xeafffffe
1003 };
1004
1005 /* make sure we have a working area */
1006 if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK)
1007 {
1008 WARNING("no working area available, falling back to slow memory reads");
1009 }
1010 else
1011 {
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);
1014 }
1015 }
1016
1017 if (!cfi_info->erase_check_algorithm)
1018 {
1019 u32 *buffer = malloc(4096);
1020
1021 for (i = 0; i < bank->num_sectors; i++)
1022 {
1023 u32 address = bank->base + bank->sectors[i].offset;
1024 u32 size = bank->sectors[i].size;
1025 u32 check = 0xffffffffU;
1026 int erased = 1;
1027
1028 while (size > 0)
1029 {
1030 u32 thisrun_size = (size > 4096) ? 4096 : size;
1031 int j;
1032
1033 target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer);
1034
1035 for (j = 0; j < thisrun_size / 4; j++)
1036 check &= buffer[j];
1037
1038 if (check != 0xffffffff)
1039 {
1040 erased = 0;
1041 break;
1042 }
1043
1044 size -= thisrun_size;
1045 address += thisrun_size;
1046 }
1047
1048 bank->sectors[i].is_erased = erased;
1049 }
1050
1051 free(buffer);
1052 }
1053 else
1054 {
1055 for (i = 0; i < bank->num_sectors; i++)
1056 {
1057 u32 address = bank->base + bank->sectors[i].offset;
1058 u32 size = bank->sectors[i].size;
1059
1060 reg_param_t reg_params[3];
1061 armv4_5_algorithm_t armv4_5_info;
1062
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;
1066
1067 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
1068 buf_set_u32(reg_params[0].value, 0, 32, address);
1069
1070 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
1071 buf_set_u32(reg_params[1].value, 0, 32, size);
1072
1073 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
1074 buf_set_u32(reg_params[2].value, 0, 32, 0xff);
1075
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;
1078
1079 if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
1080 bank->sectors[i].is_erased = 1;
1081 else
1082 bank->sectors[i].is_erased = 0;
1083
1084 destroy_reg_param(&reg_params[0]);
1085 destroy_reg_param(&reg_params[1]);
1086 destroy_reg_param(&reg_params[2]);
1087 }
1088 }
1089
1090 return ERROR_OK;
1091 }
1092
1093 int cfi_intel_protect_check(struct flash_bank_s *bank)
1094 {
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;
1098 u8 command[8];
1099 int i;
1100
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;
1104
1105 cfi_command(bank, 0x90, command);
1106 target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
1107
1108 for (i = 0; i < bank->num_sectors; i++)
1109 {
1110 u8 block_status = cfi_get_u8(bank, i, 0x2);
1111
1112 if (block_status & 1)
1113 bank->sectors[i].is_protected = 1;
1114 else
1115 bank->sectors[i].is_protected = 0;
1116 }
1117
1118 cfi_command(bank, 0xff, command);
1119 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
1120
1121 return ERROR_OK;
1122 }
1123
1124 int cfi_protect_check(struct flash_bank_s *bank)
1125 {
1126 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1127 target_t *target = cfi_info->target;
1128
1129 if (cfi_info->qry[0] != 'Q')
1130 return ERROR_FLASH_BANK_NOT_PROBED;
1131
1132 switch(cfi_info->pri_id)
1133 {
1134 case 1:
1135 case 3:
1136 return cfi_intel_protect_check(bank);
1137 break;
1138 default:
1139 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
1140 break;
1141 }
1142
1143 return ERROR_OK;
1144 }
1145
1146 int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
1147 {
1148 int printed;
1149 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1150
1151 if (cfi_info->qry[0] == -1)
1152 {
1153 printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
1154 return ERROR_OK;
1155 }
1156
1157 printed = snprintf(buf, buf_size, "\ncfi information:\n");
1158 buf += printed;
1159 buf_size -= printed;
1160
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);
1162 buf += printed;
1163 buf_size -= printed;
1164
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);
1169 buf += printed;
1170 buf_size -= printed;
1171
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);
1174 buf += printed;
1175 buf_size -= printed;
1176
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));
1181 buf += printed;
1182 buf_size -= printed;
1183
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);
1185 buf += printed;
1186 buf_size -= printed;
1187
1188 switch(cfi_info->pri_id)
1189 {
1190 case 1:
1191 case 3:
1192 cfi_intel_info(bank, buf, buf_size);
1193 break;
1194 default:
1195 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
1196 break;
1197 }
1198
1199 return ERROR_OK;
1200 }

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)