- prepare OpenOCD for branching, created ./trunk/
[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 #include "cfi.h"
21
22 #include "flash.h"
23 #include "target.h"
24 #include "log.h"
25 #include "armv4_5.h"
26 #include "algorithm.h"
27 #include "binarybuffer.h"
28 #include "types.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 int cfi_register_commands(struct command_context_s *cmd_ctx);
35 int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
36 int cfi_erase(struct flash_bank_s *bank, int first, int last);
37 int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
38 int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
39 int cfi_probe(struct flash_bank_s *bank);
40 int cfi_erase_check(struct flash_bank_s *bank);
41 int cfi_protect_check(struct flash_bank_s *bank);
42 int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
43
44 int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
45
46 #define CFI_MAX_BUS_WIDTH 4
47
48 flash_driver_t cfi_flash =
49 {
50 .name = "cfi",
51 .register_commands = cfi_register_commands,
52 .flash_bank_command = cfi_flash_bank_command,
53 .erase = cfi_erase,
54 .protect = cfi_protect,
55 .write = cfi_write,
56 .probe = cfi_probe,
57 .erase_check = cfi_erase_check,
58 .protect_check = cfi_protect_check,
59 .info = cfi_info
60 };
61
62 inline u32 flash_address(flash_bank_t *bank, int sector, u32 offset)
63 {
64 /* while the sector list isn't built, only accesses to sector 0 work */
65 if (sector == 0)
66 return bank->base + offset * bank->bus_width;
67 else
68 {
69 if (!bank->sectors)
70 {
71 ERROR("BUG: sector list not yet built");
72 exit(-1);
73 }
74 return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
75 }
76
77 }
78
79 void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
80 {
81 cfi_flash_bank_t *cfi_info = bank->driver_priv;
82 int i;
83
84 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
85 {
86 for (i = bank->bus_width; i > 0; i--)
87 {
88 *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
89 }
90 }
91 else
92 {
93 for (i = 1; i <= bank->bus_width; i++)
94 {
95 *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
96 }
97 }
98 }
99
100 /* read unsigned 8-bit value from the bank
101 * flash banks are expected to be made of similar chips
102 * the query result should be the same for all
103 */
104 u8 cfi_query_u8(flash_bank_t *bank, int sector, u32 offset)
105 {
106 cfi_flash_bank_t *cfi_info = bank->driver_priv;
107 target_t *target = cfi_info->target;
108 u8 data[CFI_MAX_BUS_WIDTH];
109
110 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
111
112 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
113 return data[0];
114 else
115 return data[bank->bus_width - 1];
116 }
117
118 /* read unsigned 8-bit value from the bank
119 * in case of a bank made of multiple chips,
120 * the individual values are ORed
121 */
122 u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset)
123 {
124 cfi_flash_bank_t *cfi_info = bank->driver_priv;
125 target_t *target = cfi_info->target;
126 u8 data[CFI_MAX_BUS_WIDTH];
127 int i;
128
129 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
130
131 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
132 {
133 for (i = 0; i < bank->bus_width / bank->chip_width; i++)
134 data[0] |= data[i];
135
136 return data[0];
137 }
138 else
139 {
140 u8 value = 0;
141 for (i = 0; i < bank->bus_width / bank->chip_width; i++)
142 value |= data[bank->bus_width - 1 - i];
143
144 return value;
145 }
146 }
147
148 u16 cfi_query_u16(flash_bank_t *bank, int sector, u32 offset)
149 {
150 cfi_flash_bank_t *cfi_info = bank->driver_priv;
151 target_t *target = cfi_info->target;
152 u8 data[CFI_MAX_BUS_WIDTH * 2];
153
154 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
155
156 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
157 return data[0] | data[bank->bus_width] << 8;
158 else
159 return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
160 }
161
162 u32 cfi_query_u32(flash_bank_t *bank, int sector, u32 offset)
163 {
164 cfi_flash_bank_t *cfi_info = bank->driver_priv;
165 target_t *target = cfi_info->target;
166 u8 data[CFI_MAX_BUS_WIDTH * 4];
167
168 target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
169
170 if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
171 return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24;
172 else
173 return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 |
174 data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
175 }
176
177 void cfi_intel_clear_status_register(flash_bank_t *bank)
178 {
179 cfi_flash_bank_t *cfi_info = bank->driver_priv;
180 target_t *target = cfi_info->target;
181 u8 command[8];
182
183 if (target->state != TARGET_HALTED)
184 {
185 ERROR("BUG: attempted to clear status register while target wasn't halted");
186 exit(-1);
187 }
188
189 cfi_command(bank, 0x50, command);
190 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
191 }
192
193 u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
194 {
195 u8 status;
196
197 while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0))
198 {
199 DEBUG("status: 0x%x", status);
200 usleep(1000);
201 }
202
203 DEBUG("status: 0x%x", status);
204
205 if (status != 0x80)
206 {
207 ERROR("status register: 0x%x", status);
208 if (status & 0x2)
209 ERROR("Block Lock-Bit Detected, Operation Abort");
210 if (status & 0x4)
211 ERROR("Program suspended");
212 if (status & 0x8)
213 ERROR("Low Programming Voltage Detected, Operation Aborted");
214 if (status & 0x10)
215 ERROR("Program Error / Error in Setting Lock-Bit");
216 if (status & 0x20)
217 ERROR("Error in Block Erasure or Clear Lock-Bits");
218 if (status & 0x40)
219 ERROR("Block Erase Suspended");
220
221 cfi_intel_clear_status_register(bank);
222 }
223
224 return status;
225 }
226 int cfi_read_intel_pri_ext(flash_bank_t *bank)
227 {
228 cfi_flash_bank_t *cfi_info = bank->driver_priv;
229 cfi_intel_pri_ext_t *pri_ext = malloc(sizeof(cfi_intel_pri_ext_t));
230 target_t *target = cfi_info->target;
231 u8 command[8];
232
233 cfi_info->pri_ext = pri_ext;
234
235 pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
236 pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
237 pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
238
239 if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
240 {
241 cfi_command(bank, 0xf0, command);
242 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
243 cfi_command(bank, 0xff, command);
244 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
245 return ERROR_FLASH_BANK_INVALID;
246 }
247
248 pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
249 pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
250
251 DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
252
253 pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5);
254 pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
255 pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa);
256
257 DEBUG("feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
258
259 pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc);
260 pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd);
261
262 DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
263 (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
264 (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
265
266 pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe);
267 if (pri_ext->num_protection_fields != 1)
268 {
269 WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields);
270 }
271
272 pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf);
273 pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11);
274 pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12);
275
276 DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
277
278 return ERROR_OK;
279 }
280
281 int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
282 {
283 int printed;
284 cfi_flash_bank_t *cfi_info = bank->driver_priv;
285 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
286
287 printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
288 buf += printed;
289 buf_size -= printed;
290
291 printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
292 buf += printed;
293 buf_size -= printed;
294
295 printed = snprintf(buf, buf_size, "feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
296 buf += printed;
297 buf_size -= printed;
298
299 printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
300 (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
301 (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
302 buf += printed;
303 buf_size -= printed;
304
305 printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
306
307 return ERROR_OK;
308 }
309
310 int cfi_register_commands(struct command_context_s *cmd_ctx)
311 {
312 command_t *cfi_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
313 /*
314 register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
315 "print part id of cfi flash bank <num>");
316 */
317 return ERROR_OK;
318 }
319
320 /* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#>
321 */
322 int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
323 {
324 cfi_flash_bank_t *cfi_info;
325
326 if (argc < 6)
327 {
328 WARNING("incomplete flash_bank cfi configuration");
329 return ERROR_FLASH_BANK_INVALID;
330 }
331
332 cfi_info = malloc(sizeof(cfi_flash_bank_t));
333 bank->driver_priv = cfi_info;
334
335 cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
336 if (!cfi_info->target)
337 {
338 ERROR("no target '%i' configured", args[5]);
339 exit(-1);
340 }
341
342 /* bank wasn't probed yet */
343 cfi_info->qry[0] = -1;
344
345 return ERROR_OK;
346 }
347
348 int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
349 {
350 cfi_flash_bank_t *cfi_info = bank->driver_priv;
351 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
352 target_t *target = cfi_info->target;
353 u8 command[8];
354 int i;
355
356 cfi_intel_clear_status_register(bank);
357
358 for (i = first; i <= last; i++)
359 {
360 cfi_command(bank, 0x20, command);
361 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
362
363 cfi_command(bank, 0xd0, command);
364 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
365
366 if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80)
367 bank->sectors[i].is_erased = 1;
368 else
369 {
370 cfi_command(bank, 0xff, command);
371 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
372
373 ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base);
374 return ERROR_FLASH_OPERATION_FAILED;
375 }
376 }
377
378 cfi_command(bank, 0xff, command);
379 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
380
381 return ERROR_OK;
382 }
383
384 int cfi_erase(struct flash_bank_s *bank, int first, int last)
385 {
386 cfi_flash_bank_t *cfi_info = bank->driver_priv;
387
388 if (cfi_info->target->state != TARGET_HALTED)
389 {
390 return ERROR_TARGET_NOT_HALTED;
391 }
392
393 if ((first < 0) || (last < first) || (last >= bank->num_sectors))
394 {
395 return ERROR_FLASH_SECTOR_INVALID;
396 }
397
398 if (cfi_info->qry[0] != 'Q')
399 return ERROR_FLASH_BANK_NOT_PROBED;
400
401 switch(cfi_info->pri_id)
402 {
403 case 1:
404 case 3:
405 return cfi_intel_erase(bank, first, last);
406 break;
407 default:
408 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
409 break;
410 }
411
412 return ERROR_OK;
413 }
414
415 int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
416 {
417 cfi_flash_bank_t *cfi_info = bank->driver_priv;
418 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
419 target_t *target = cfi_info->target;
420 u8 command[8];
421 int i;
422
423 if (!(pri_ext->feature_support & 0x28))
424 return ERROR_FLASH_OPERATION_FAILED;
425
426 cfi_intel_clear_status_register(bank);
427
428 for (i = first; i <= last; i++)
429 {
430 cfi_command(bank, 0x60, command);
431 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
432 if (set)
433 {
434 cfi_command(bank, 0x01, command);
435 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
436 bank->sectors[i].is_protected = 1;
437 }
438 else
439 {
440 cfi_command(bank, 0xd0, command);
441 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
442 bank->sectors[i].is_protected = 0;
443 }
444
445 cfi_intel_wait_status_busy(bank, 100);
446 }
447
448 /* if the device doesn't support individual block lock bits set/clear,
449 * all blocks have been unlocked in parallel, so we set those that should be protected
450 */
451 if ((!set) && (!(pri_ext->feature_support & 0x20)))
452 {
453 for (i = 0; i < bank->num_sectors; i++)
454 {
455 cfi_intel_clear_status_register(bank);
456 cfi_command(bank, 0x60, command);
457 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
458 if (bank->sectors[i].is_protected == 1)
459 {
460 cfi_command(bank, 0x01, command);
461 target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
462 }
463
464 cfi_intel_wait_status_busy(bank, 100);
465 }
466 }
467
468 cfi_command(bank, 0xff, command);
469 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
470
471 return ERROR_OK;
472 }
473
474 int cfi_protect(struct flash_bank_s *bank, int set, int first, int last)
475 {
476 cfi_flash_bank_t *cfi_info = bank->driver_priv;
477
478 if (cfi_info->target->state != TARGET_HALTED)
479 {
480 return ERROR_TARGET_NOT_HALTED;
481 }
482
483 if ((first < 0) || (last < first) || (last >= bank->num_sectors))
484 {
485 return ERROR_FLASH_SECTOR_INVALID;
486 }
487
488 if (cfi_info->qry[0] != 'Q')
489 return ERROR_FLASH_BANK_NOT_PROBED;
490
491 switch(cfi_info->pri_id)
492 {
493 case 1:
494 case 3:
495 cfi_intel_protect(bank, set, first, last);
496 break;
497 default:
498 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
499 break;
500 }
501
502 return ERROR_OK;
503 }
504
505 void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte)
506 {
507 cfi_flash_bank_t *cfi_info = bank->driver_priv;
508 target_t *target = cfi_info->target;
509
510 int i;
511
512 if (target->endianness == TARGET_LITTLE_ENDIAN)
513 {
514 /* shift bytes */
515 for (i = 0; i < bank->bus_width - 1; i++)
516 word[i] = word[i + 1];
517 word[bank->bus_width - 1] = byte;
518 }
519 else
520 {
521 /* shift bytes */
522 for (i = bank->bus_width - 1; i > 0; i--)
523 word[i] = word[i - 1];
524 word[0] = byte;
525 }
526 }
527
528 int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count)
529 {
530 cfi_flash_bank_t *cfi_info = bank->driver_priv;
531 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
532 target_t *target = cfi_info->target;
533 reg_param_t reg_params[5];
534 armv4_5_algorithm_t armv4_5_info;
535 working_area_t *source;
536 u32 buffer_size = 32768;
537 u8 write_command[CFI_MAX_BUS_WIDTH];
538 int i;
539 int retval;
540
541 u32 word_32_code[] = {
542 0xe4904004, /* loop: ldr r4, [r0], #4 */
543 0xe5813000, /* str r3, [r1] */
544 0xe5814000, /* str r4, [r1] */
545 0xe5914000, /* busy ldr r4, [r1] */
546 0xe3140080, /* tst r4, #0x80 */
547 0x0afffffc, /* beq busy */
548 0xe314007f, /* tst r4, #0x7f */
549 0x1a000003, /* bne done */
550 0xe2522001, /* subs r2, r2, #1 */
551 0x0a000001, /* beq done */
552 0xe2811004, /* add r1, r1 #4 */
553 0xeafffff3, /* b loop */
554 0xeafffffe, /* done: b -2 */
555 };
556
557 u32 word_16_code[] = {
558 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
559 0xe1c130b0, /* strh r3, [r1] */
560 0xe1c140b0, /* strh r4, [r1] */
561 0xe1d140b0, /* busy ldrh r4, [r1] */
562 0xe3140080, /* tst r4, #0x80 */
563 0x0afffffc, /* beq busy */
564 0xe314007f, /* tst r4, #0x7f */
565 0x1a000003, /* bne done */
566 0xe2522001, /* subs r2, r2, #1 */
567 0x0a000001, /* beq done */
568 0xe2811002, /* add r1, r1 #2 */
569 0xeafffff3, /* b loop */
570 0xeafffffe, /* done: b -2 */
571 };
572
573 u32 word_8_code[] = {
574 0xe4d04001, /* loop: ldrb r4, [r0], #1 */
575 0xe5c13000, /* strb r3, [r1] */
576 0xe5c14000, /* strb r4, [r1] */
577 0xe5d14000, /* busy ldrb r4, [r1] */
578 0xe3140080, /* tst r4, #0x80 */
579 0x0afffffc, /* beq busy */
580 0xe314007f, /* tst r4, #0x7f */
581 0x1a000003, /* bne done */
582 0xe2522001, /* subs r2, r2, #1 */
583 0x0a000001, /* beq done */
584 0xe2811001, /* add r1, r1 #1 */
585 0xeafffff3, /* b loop */
586 0xeafffffe, /* done: b -2 */
587 };
588
589 cfi_intel_clear_status_register(bank);
590
591 armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
592 armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
593 armv4_5_info.core_state = ARMV4_5_STATE_ARM;
594
595 /* flash write code */
596 if (!cfi_info->write_algorithm)
597 {
598 if (target_alloc_working_area(target, 4 * 13, &cfi_info->write_algorithm) != ERROR_OK)
599 {
600 WARNING("no working area available, can't do block memory writes");
601 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
602 };
603
604 /* write algorithm code to working area */
605 if (bank->bus_width == 1)
606 {
607 target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_8_code);
608 }
609 else if (bank->bus_width == 2)
610 {
611 target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_16_code);
612 }
613 else if (bank->bus_width == 4)
614 {
615 target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_32_code);
616 }
617 else
618 {
619 return ERROR_FLASH_OPERATION_FAILED;
620 }
621 }
622
623 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
624 {
625 buffer_size /= 2;
626 if (buffer_size <= 256)
627 {
628 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
629 if (cfi_info->write_algorithm)
630 target_free_working_area(target, cfi_info->write_algorithm);
631
632 WARNING("no large enough working area available, can't do block memory writes");
633 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
634 }
635 };
636
637 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
638 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
639 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
640 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
641 init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
642
643 while (count > 0)
644 {
645 u32 thisrun_count = (count > buffer_size) ? buffer_size : count;
646
647 target_write_buffer(target, source->address, thisrun_count, buffer);
648
649 buf_set_u32(reg_params[0].value, 0, 32, source->address);
650 buf_set_u32(reg_params[1].value, 0, 32, address);
651 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
652 cfi_command(bank, 0x40, write_command);
653 buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32));
654
655 if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (12 * 4), 10000, &armv4_5_info)) != ERROR_OK)
656 {
657 cfi_intel_clear_status_register(bank);
658 return ERROR_FLASH_OPERATION_FAILED;
659 }
660
661 if (buf_get_u32(reg_params[4].value, 0, 32) != 0x80)
662 {
663 /* read status register (outputs debug inforation) */
664 cfi_intel_wait_status_busy(bank, 100);
665 cfi_intel_clear_status_register(bank);
666 return ERROR_FLASH_OPERATION_FAILED;
667 }
668
669 buffer += thisrun_count;
670 address += thisrun_count;
671 count -= thisrun_count;
672 }
673
674 destroy_reg_param(&reg_params[0]);
675 destroy_reg_param(&reg_params[1]);
676 destroy_reg_param(&reg_params[2]);
677 destroy_reg_param(&reg_params[3]);
678 destroy_reg_param(&reg_params[4]);
679
680 return ERROR_OK;
681 }
682
683 int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
684 {
685 cfi_flash_bank_t *cfi_info = bank->driver_priv;
686 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
687 target_t *target = cfi_info->target;
688 u8 command[8];
689
690 cfi_intel_clear_status_register(bank);
691 cfi_command(bank, 0x40, command);
692 target->type->write_memory(target, address, bank->bus_width, 1, command);
693
694 target->type->write_memory(target, address, bank->bus_width, 1, word);
695
696 if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
697 {
698 cfi_command(bank, 0xff, command);
699 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
700
701 ERROR("couldn't write word at base 0x%x, address %x", bank->base, address);
702 return ERROR_FLASH_OPERATION_FAILED;
703 }
704
705 return ERROR_OK;
706 }
707
708 int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
709 {
710 cfi_flash_bank_t *cfi_info = bank->driver_priv;
711 target_t *target = cfi_info->target;
712
713 switch(cfi_info->pri_id)
714 {
715 case 1:
716 case 3:
717 return cfi_intel_write_word(bank, word, address);
718 break;
719 default:
720 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
721 break;
722 }
723
724 return ERROR_FLASH_OPERATION_FAILED;
725 }
726
727 int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
728 {
729 cfi_flash_bank_t *cfi_info = bank->driver_priv;
730 target_t *target = cfi_info->target;
731 u32 address = bank->base + offset; /* address of first byte to be programmed */
732 u32 write_p, copy_p;
733 int align; /* number of unaligned bytes */
734 u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */
735 int i;
736 int retval;
737
738 if (cfi_info->target->state != TARGET_HALTED)
739 {
740 return ERROR_TARGET_NOT_HALTED;
741 }
742
743 if (offset + count > bank->size)
744 return ERROR_FLASH_DST_OUT_OF_BANK;
745
746 if (cfi_info->qry[0] != 'Q')
747 return ERROR_FLASH_BANK_NOT_PROBED;
748
749 /* start at the first byte of the first word (bus_width size) */
750 write_p = address & ~(bank->bus_width - 1);
751 if ((align = address - write_p) != 0)
752 {
753 for (i = 0; i < bank->bus_width; i++)
754 current_word[i] = 0;
755 copy_p = write_p;
756
757 /* copy bytes before the first write address */
758 for (i = 0; i < align; ++i, ++copy_p)
759 {
760 u8 byte;
761 target->type->read_memory(target, copy_p, 1, 1, &byte);
762 cfi_add_byte(bank, current_word, byte);
763 }
764
765 /* add bytes from the buffer */
766 for (; (i < bank->bus_width) && (count > 0); i++)
767 {
768 cfi_add_byte(bank, current_word, *buffer++);
769 count--;
770 copy_p++;
771 }
772
773 /* if the buffer is already finished, copy bytes after the last write address */
774 for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
775 {
776 u8 byte;
777 target->type->read_memory(target, copy_p, 1, 1, &byte);
778 cfi_add_byte(bank, current_word, byte);
779 }
780
781 retval = cfi_write_word(bank, current_word, write_p);
782 if (retval != ERROR_OK)
783 return retval;
784 write_p = copy_p;
785 }
786
787 /* handle blocks of bus_size aligned bytes */
788 switch(cfi_info->pri_id)
789 {
790 /* try block writes (fails without working area) */
791 case 1:
792 case 3:
793 retval = cfi_intel_write_block(bank, buffer, write_p, count);
794 break;
795 default:
796 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
797 break;
798 }
799 if (retval != ERROR_OK)
800 {
801 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
802 {
803 /* fall back to memory writes */
804 while (count > bank->bus_width)
805 {
806 for (i = 0; i < bank->bus_width; i++)
807 current_word[i] = 0;
808
809 for (i = 0; i < bank->bus_width; i++)
810 {
811 cfi_add_byte(bank, current_word, *buffer++);
812 }
813
814 retval = cfi_write_word(bank, current_word, write_p);
815 if (retval != ERROR_OK)
816 return retval;
817 write_p += bank->bus_width;
818 count -= bank->bus_width;
819 }
820 }
821 else
822 return retval;
823 }
824
825 /* handle unaligned tail bytes */
826 if (count > 0)
827 {
828 copy_p = write_p;
829 for (i = 0; i < bank->bus_width; i++)
830 current_word[i] = 0;
831
832 for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
833 {
834 cfi_add_byte(bank, current_word, *buffer++);
835 count--;
836 }
837 for (; i < bank->bus_width; ++i, ++copy_p)
838 {
839 u8 byte;
840 target->type->read_memory(target, copy_p, 1, 1, &byte);
841 cfi_add_byte(bank, current_word, byte);
842 }
843 retval = cfi_write_word(bank, current_word, write_p);
844 if (retval != ERROR_OK)
845 return retval;
846 }
847
848 /* return to read array mode */
849 cfi_command(bank, 0xf0, current_word);
850 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
851 cfi_command(bank, 0xff, current_word);
852 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
853
854 return ERROR_OK;
855 }
856
857 int cfi_probe(struct flash_bank_s *bank)
858 {
859 cfi_flash_bank_t *cfi_info = bank->driver_priv;
860 target_t *target = cfi_info->target;
861 u8 command[8];
862
863
864 cfi_command(bank, 0x98, command);
865 target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
866
867 cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
868 cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
869 cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
870
871 if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
872 {
873 cfi_command(bank, 0xf0, command);
874 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
875 cfi_command(bank, 0xff, command);
876 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
877 return ERROR_FLASH_BANK_INVALID;
878 }
879
880 cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
881 cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
882 cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
883 cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
884
885 DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
886
887 cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
888 cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
889 cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
890 cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
891 cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
892 cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
893 cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
894 cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
895 cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
896 cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
897 cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
898 cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
899
900 DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
901 (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
902 (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
903 (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
904 (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
905 DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
906 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
907 DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
908 (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
909 (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
910 (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
911
912 cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27);
913 cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
914 cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
915 cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
916
917 DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
918
919 if (1 << cfi_info->dev_size != bank->size)
920 {
921 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
922 }
923
924 if (cfi_info->num_erase_regions)
925 {
926 int i;
927 int num_sectors = 0;
928 int sector = 0;
929 u32 offset = 0;
930 cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
931
932 for (i = 0; i < cfi_info->num_erase_regions; i++)
933 {
934 cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
935 DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
936
937 num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
938 }
939
940 bank->num_sectors = num_sectors;
941 bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
942 for (i = 0; i < cfi_info->num_erase_regions; i++)
943 {
944 int j;
945 for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
946 {
947 bank->sectors[sector].offset = offset;
948 bank->sectors[sector].size = (cfi_info->erase_region_info[i] >> 16) * 256;
949 offset += bank->sectors[sector].size;
950 bank->sectors[sector].is_erased = -1;
951 bank->sectors[sector].is_protected = -1;
952 sector++;
953 }
954 }
955 }
956 else
957 {
958 cfi_info->erase_region_info = NULL;
959 }
960
961 switch(cfi_info->pri_id)
962 {
963 case 1:
964 case 3:
965 cfi_read_intel_pri_ext(bank);
966 break;
967 default:
968 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
969 break;
970 }
971
972 /* return to read array mode */
973 cfi_command(bank, 0xf0, command);
974 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
975 cfi_command(bank, 0xff, command);
976 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
977
978 return ERROR_OK;
979 }
980
981 int cfi_erase_check(struct flash_bank_s *bank)
982 {
983 cfi_flash_bank_t *cfi_info = bank->driver_priv;
984 target_t *target = cfi_info->target;
985 int i;
986 int retval;
987
988 if (!cfi_info->erase_check_algorithm)
989 {
990 u32 erase_check_code[] =
991 {
992 0xe4d03001,
993 0xe0022003,
994 0xe2511001,
995 0x1afffffb,
996 0xeafffffe
997 };
998
999 /* make sure we have a working area */
1000 if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK)
1001 {
1002 WARNING("no working area available, falling back to slow memory reads");
1003 }
1004 else
1005 {
1006 /* write algorithm code to working area */
1007 target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, (u8*)erase_check_code);
1008 }
1009 }
1010
1011 if (!cfi_info->erase_check_algorithm)
1012 {
1013 u32 *buffer = malloc(4096);
1014
1015 for (i = 0; i < bank->num_sectors; i++)
1016 {
1017 u32 address = bank->base + bank->sectors[i].offset;
1018 u32 size = bank->sectors[i].size;
1019 u32 check = 0xffffffffU;
1020 int erased = 1;
1021
1022 while (size > 0)
1023 {
1024 u32 thisrun_size = (size > 4096) ? 4096 : size;
1025 int j;
1026
1027 target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer);
1028
1029 for (j = 0; j < thisrun_size / 4; j++)
1030 check &= buffer[j];
1031
1032 if (check != 0xffffffff)
1033 {
1034 erased = 0;
1035 break;
1036 }
1037
1038 size -= thisrun_size;
1039 address += thisrun_size;
1040 }
1041
1042 bank->sectors[i].is_erased = erased;
1043 }
1044
1045 free(buffer);
1046 }
1047 else
1048 {
1049 for (i = 0; i < bank->num_sectors; i++)
1050 {
1051 u32 address = bank->base + bank->sectors[i].offset;
1052 u32 size = bank->sectors[i].size;
1053
1054 reg_param_t reg_params[3];
1055 armv4_5_algorithm_t armv4_5_info;
1056
1057 armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
1058 armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
1059 armv4_5_info.core_state = ARMV4_5_STATE_ARM;
1060
1061 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
1062 buf_set_u32(reg_params[0].value, 0, 32, address);
1063
1064 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
1065 buf_set_u32(reg_params[1].value, 0, 32, size);
1066
1067 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
1068 buf_set_u32(reg_params[2].value, 0, 32, 0xff);
1069
1070 if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
1071 return ERROR_FLASH_OPERATION_FAILED;
1072
1073 if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
1074 bank->sectors[i].is_erased = 1;
1075 else
1076 bank->sectors[i].is_erased = 0;
1077
1078 destroy_reg_param(&reg_params[0]);
1079 destroy_reg_param(&reg_params[1]);
1080 destroy_reg_param(&reg_params[2]);
1081 }
1082 }
1083
1084 return ERROR_OK;
1085 }
1086
1087 int cfi_intel_protect_check(struct flash_bank_s *bank)
1088 {
1089 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1090 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
1091 target_t *target = cfi_info->target;
1092 u8 command[8];
1093 int i;
1094
1095 /* check if block lock bits are supported on this device */
1096 if (!(pri_ext->blk_status_reg_mask & 0x1))
1097 return ERROR_FLASH_OPERATION_FAILED;
1098
1099 cfi_command(bank, 0x90, command);
1100 target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
1101
1102 for (i = 0; i < bank->num_sectors; i++)
1103 {
1104 u8 block_status = cfi_get_u8(bank, i, 0x2);
1105
1106 if (block_status & 1)
1107 bank->sectors[i].is_protected = 1;
1108 else
1109 bank->sectors[i].is_protected = 0;
1110 }
1111
1112 cfi_command(bank, 0xff, command);
1113 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
1114
1115 return ERROR_OK;
1116 }
1117
1118 int cfi_protect_check(struct flash_bank_s *bank)
1119 {
1120 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1121 target_t *target = cfi_info->target;
1122
1123 if (cfi_info->qry[0] != 'Q')
1124 return ERROR_FLASH_BANK_NOT_PROBED;
1125
1126 switch(cfi_info->pri_id)
1127 {
1128 case 1:
1129 case 3:
1130 return cfi_intel_protect_check(bank);
1131 break;
1132 default:
1133 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
1134 break;
1135 }
1136
1137 return ERROR_OK;
1138 }
1139
1140 int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
1141 {
1142 int printed;
1143 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1144
1145 if (cfi_info->qry[0] == -1)
1146 {
1147 printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
1148 return ERROR_OK;
1149 }
1150
1151 printed = snprintf(buf, buf_size, "\ncfi information:\n");
1152 buf += printed;
1153 buf_size -= printed;
1154
1155 printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
1156 buf += printed;
1157 buf_size -= printed;
1158
1159 printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
1160 (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
1161 (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
1162 (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
1163 buf += printed;
1164 buf_size -= printed;
1165
1166 printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
1167 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
1168 buf += printed;
1169 buf_size -= printed;
1170
1171 printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
1172 (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
1173 (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
1174 (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
1175 buf += printed;
1176 buf_size -= printed;
1177
1178 printed = snprintf(buf, buf_size, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
1179 buf += printed;
1180 buf_size -= printed;
1181
1182 switch(cfi_info->pri_id)
1183 {
1184 case 1:
1185 case 3:
1186 cfi_intel_info(bank, buf, buf_size);
1187 break;
1188 default:
1189 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
1190 break;
1191 }
1192
1193 return ERROR_OK;
1194 }

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)