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

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)