bb548c22d1d51160312886ef67f995293f92a8b0
[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 target_free_working_area(target, source);
689
690 destroy_reg_param(&reg_params[0]);
691 destroy_reg_param(&reg_params[1]);
692 destroy_reg_param(&reg_params[2]);
693 destroy_reg_param(&reg_params[3]);
694 destroy_reg_param(&reg_params[4]);
695
696 return ERROR_OK;
697 }
698
699 int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
700 {
701 cfi_flash_bank_t *cfi_info = bank->driver_priv;
702 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
703 target_t *target = cfi_info->target;
704 u8 command[8];
705
706 cfi_intel_clear_status_register(bank);
707 cfi_command(bank, 0x40, command);
708 target->type->write_memory(target, address, bank->bus_width, 1, command);
709
710 target->type->write_memory(target, address, bank->bus_width, 1, word);
711
712 if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
713 {
714 cfi_command(bank, 0xff, command);
715 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
716
717 ERROR("couldn't write word at base 0x%x, address %x", bank->base, address);
718 return ERROR_FLASH_OPERATION_FAILED;
719 }
720
721 return ERROR_OK;
722 }
723
724 int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
725 {
726 cfi_flash_bank_t *cfi_info = bank->driver_priv;
727 target_t *target = cfi_info->target;
728
729 switch(cfi_info->pri_id)
730 {
731 case 1:
732 case 3:
733 return cfi_intel_write_word(bank, word, address);
734 break;
735 default:
736 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
737 break;
738 }
739
740 return ERROR_FLASH_OPERATION_FAILED;
741 }
742
743 int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
744 {
745 cfi_flash_bank_t *cfi_info = bank->driver_priv;
746 target_t *target = cfi_info->target;
747 u32 address = bank->base + offset; /* address of first byte to be programmed */
748 u32 write_p, copy_p;
749 int align; /* number of unaligned bytes */
750 u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */
751 int i;
752 int retval;
753
754 if (cfi_info->target->state != TARGET_HALTED)
755 {
756 return ERROR_TARGET_NOT_HALTED;
757 }
758
759 if (offset + count > bank->size)
760 return ERROR_FLASH_DST_OUT_OF_BANK;
761
762 if (cfi_info->qry[0] != 'Q')
763 return ERROR_FLASH_BANK_NOT_PROBED;
764
765 /* start at the first byte of the first word (bus_width size) */
766 write_p = address & ~(bank->bus_width - 1);
767 if ((align = address - write_p) != 0)
768 {
769 for (i = 0; i < bank->bus_width; i++)
770 current_word[i] = 0;
771 copy_p = write_p;
772
773 /* copy bytes before the first write address */
774 for (i = 0; i < align; ++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 /* add bytes from the buffer */
782 for (; (i < bank->bus_width) && (count > 0); i++)
783 {
784 cfi_add_byte(bank, current_word, *buffer++);
785 count--;
786 copy_p++;
787 }
788
789 /* if the buffer is already finished, copy bytes after the last write address */
790 for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
791 {
792 u8 byte;
793 target->type->read_memory(target, copy_p, 1, 1, &byte);
794 cfi_add_byte(bank, current_word, byte);
795 }
796
797 retval = cfi_write_word(bank, current_word, write_p);
798 if (retval != ERROR_OK)
799 return retval;
800 write_p = copy_p;
801 }
802
803 /* handle blocks of bus_size aligned bytes */
804 switch(cfi_info->pri_id)
805 {
806 /* try block writes (fails without working area) */
807 case 1:
808 case 3:
809 retval = cfi_intel_write_block(bank, buffer, write_p, count);
810 break;
811 default:
812 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
813 break;
814 }
815 if (retval != ERROR_OK)
816 {
817 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
818 {
819 /* fall back to memory writes */
820 while (count > bank->bus_width)
821 {
822 for (i = 0; i < bank->bus_width; i++)
823 current_word[i] = 0;
824
825 for (i = 0; i < bank->bus_width; i++)
826 {
827 cfi_add_byte(bank, current_word, *buffer++);
828 }
829
830 retval = cfi_write_word(bank, current_word, write_p);
831 if (retval != ERROR_OK)
832 return retval;
833 write_p += bank->bus_width;
834 count -= bank->bus_width;
835 }
836 }
837 else
838 return retval;
839 }
840
841 /* handle unaligned tail bytes */
842 if (count > 0)
843 {
844 copy_p = write_p;
845 for (i = 0; i < bank->bus_width; i++)
846 current_word[i] = 0;
847
848 for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
849 {
850 cfi_add_byte(bank, current_word, *buffer++);
851 count--;
852 }
853 for (; i < bank->bus_width; ++i, ++copy_p)
854 {
855 u8 byte;
856 target->type->read_memory(target, copy_p, 1, 1, &byte);
857 cfi_add_byte(bank, current_word, byte);
858 }
859 retval = cfi_write_word(bank, current_word, write_p);
860 if (retval != ERROR_OK)
861 return retval;
862 }
863
864 /* return to read array mode */
865 cfi_command(bank, 0xf0, current_word);
866 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
867 cfi_command(bank, 0xff, current_word);
868 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
869
870 return ERROR_OK;
871 }
872
873 int cfi_probe(struct flash_bank_s *bank)
874 {
875 cfi_flash_bank_t *cfi_info = bank->driver_priv;
876 target_t *target = cfi_info->target;
877 u8 command[8];
878
879
880 cfi_command(bank, 0x98, command);
881 target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
882
883 cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
884 cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
885 cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
886
887 DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
888
889 if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
890 {
891 cfi_command(bank, 0xf0, command);
892 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
893 cfi_command(bank, 0xff, command);
894 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
895 return ERROR_FLASH_BANK_INVALID;
896 }
897
898 cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
899 cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
900 cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
901 cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
902
903 DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
904
905 cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
906 cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
907 cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
908 cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
909 cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
910 cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
911 cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
912 cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
913 cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
914 cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
915 cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
916 cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
917
918 DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
919 (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
920 (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
921 (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
922 (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
923 DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
924 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
925 DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
926 (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
927 (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
928 (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
929
930 cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27);
931 cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
932 cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
933 cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
934
935 DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
936
937 if (1 << cfi_info->dev_size != bank->size)
938 {
939 WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
940 }
941
942 if (cfi_info->num_erase_regions)
943 {
944 int i;
945 int num_sectors = 0;
946 int sector = 0;
947 u32 offset = 0;
948 cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
949
950 for (i = 0; i < cfi_info->num_erase_regions; i++)
951 {
952 cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
953 DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
954
955 num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
956 }
957
958 bank->num_sectors = num_sectors;
959 bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
960 for (i = 0; i < cfi_info->num_erase_regions; i++)
961 {
962 int j;
963 for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
964 {
965 bank->sectors[sector].offset = offset;
966 bank->sectors[sector].size = (cfi_info->erase_region_info[i] >> 16) * 256;
967 offset += bank->sectors[sector].size;
968 bank->sectors[sector].is_erased = -1;
969 bank->sectors[sector].is_protected = -1;
970 sector++;
971 }
972 }
973 }
974 else
975 {
976 cfi_info->erase_region_info = NULL;
977 }
978
979 switch(cfi_info->pri_id)
980 {
981 case 1:
982 case 3:
983 cfi_read_intel_pri_ext(bank);
984 break;
985 default:
986 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
987 break;
988 }
989
990 /* return to read array mode */
991 cfi_command(bank, 0xf0, command);
992 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
993 cfi_command(bank, 0xff, command);
994 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
995
996 return ERROR_OK;
997 }
998
999 int cfi_erase_check(struct flash_bank_s *bank)
1000 {
1001 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1002 target_t *target = cfi_info->target;
1003 int i;
1004 int retval;
1005
1006 if (!cfi_info->erase_check_algorithm)
1007 {
1008 u32 erase_check_code[] =
1009 {
1010 0xe4d03001, /* ldrb r3, [r0], #1 */
1011 0xe0022003, /* and r2, r2, r3 */
1012 0xe2511001, /* subs r1, r1, #1 */
1013 0x1afffffb, /* b -4 */
1014 0xeafffffe /* b 0 */
1015 };
1016
1017 /* make sure we have a working area */
1018 if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK)
1019 {
1020 WARNING("no working area available, falling back to slow memory reads");
1021 }
1022 else
1023 {
1024 u8 erase_check_code_buf[5 * 4];
1025
1026 for (i = 0; i < 5; i++)
1027 target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]);
1028
1029 /* write algorithm code to working area */
1030 target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, erase_check_code_buf);
1031 }
1032 }
1033
1034 if (!cfi_info->erase_check_algorithm)
1035 {
1036 u32 *buffer = malloc(4096);
1037
1038 for (i = 0; i < bank->num_sectors; i++)
1039 {
1040 u32 address = bank->base + bank->sectors[i].offset;
1041 u32 size = bank->sectors[i].size;
1042 u32 check = 0xffffffffU;
1043 int erased = 1;
1044
1045 while (size > 0)
1046 {
1047 u32 thisrun_size = (size > 4096) ? 4096 : size;
1048 int j;
1049
1050 target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer);
1051
1052 for (j = 0; j < thisrun_size / 4; j++)
1053 check &= buffer[j];
1054
1055 if (check != 0xffffffff)
1056 {
1057 erased = 0;
1058 break;
1059 }
1060
1061 size -= thisrun_size;
1062 address += thisrun_size;
1063 }
1064
1065 bank->sectors[i].is_erased = erased;
1066 }
1067
1068 free(buffer);
1069 }
1070 else
1071 {
1072 for (i = 0; i < bank->num_sectors; i++)
1073 {
1074 u32 address = bank->base + bank->sectors[i].offset;
1075 u32 size = bank->sectors[i].size;
1076
1077 reg_param_t reg_params[3];
1078 armv4_5_algorithm_t armv4_5_info;
1079
1080 armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
1081 armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
1082 armv4_5_info.core_state = ARMV4_5_STATE_ARM;
1083
1084 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
1085 buf_set_u32(reg_params[0].value, 0, 32, address);
1086
1087 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
1088 buf_set_u32(reg_params[1].value, 0, 32, size);
1089
1090 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
1091 buf_set_u32(reg_params[2].value, 0, 32, 0xff);
1092
1093 if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
1094 return ERROR_FLASH_OPERATION_FAILED;
1095
1096 if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
1097 bank->sectors[i].is_erased = 1;
1098 else
1099 bank->sectors[i].is_erased = 0;
1100
1101 destroy_reg_param(&reg_params[0]);
1102 destroy_reg_param(&reg_params[1]);
1103 destroy_reg_param(&reg_params[2]);
1104 }
1105 }
1106
1107 return ERROR_OK;
1108 }
1109
1110 int cfi_intel_protect_check(struct flash_bank_s *bank)
1111 {
1112 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1113 cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
1114 target_t *target = cfi_info->target;
1115 u8 command[8];
1116 int i;
1117
1118 /* check if block lock bits are supported on this device */
1119 if (!(pri_ext->blk_status_reg_mask & 0x1))
1120 return ERROR_FLASH_OPERATION_FAILED;
1121
1122 cfi_command(bank, 0x90, command);
1123 target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
1124
1125 for (i = 0; i < bank->num_sectors; i++)
1126 {
1127 u8 block_status = cfi_get_u8(bank, i, 0x2);
1128
1129 if (block_status & 1)
1130 bank->sectors[i].is_protected = 1;
1131 else
1132 bank->sectors[i].is_protected = 0;
1133 }
1134
1135 cfi_command(bank, 0xff, command);
1136 target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
1137
1138 return ERROR_OK;
1139 }
1140
1141 int cfi_protect_check(struct flash_bank_s *bank)
1142 {
1143 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1144 target_t *target = cfi_info->target;
1145
1146 if (cfi_info->qry[0] != 'Q')
1147 return ERROR_FLASH_BANK_NOT_PROBED;
1148
1149 switch(cfi_info->pri_id)
1150 {
1151 case 1:
1152 case 3:
1153 return cfi_intel_protect_check(bank);
1154 break;
1155 default:
1156 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
1157 break;
1158 }
1159
1160 return ERROR_OK;
1161 }
1162
1163 int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
1164 {
1165 int printed;
1166 cfi_flash_bank_t *cfi_info = bank->driver_priv;
1167
1168 if (cfi_info->qry[0] == -1)
1169 {
1170 printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
1171 return ERROR_OK;
1172 }
1173
1174 printed = snprintf(buf, buf_size, "\ncfi information:\n");
1175 buf += printed;
1176 buf_size -= printed;
1177
1178 printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
1179 buf += printed;
1180 buf_size -= printed;
1181
1182 printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
1183 (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
1184 (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
1185 (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
1186 buf += printed;
1187 buf_size -= printed;
1188
1189 printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
1190 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
1191 buf += printed;
1192 buf_size -= printed;
1193
1194 printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
1195 (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
1196 (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
1197 (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
1198 buf += printed;
1199 buf_size -= printed;
1200
1201 printed = snprintf(buf, buf_size, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
1202 buf += printed;
1203 buf_size -= printed;
1204
1205 switch(cfi_info->pri_id)
1206 {
1207 case 1:
1208 case 3:
1209 cfi_intel_info(bank, buf, buf_size);
1210 break;
1211 default:
1212 ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
1213 break;
1214 }
1215
1216 return ERROR_OK;
1217 }

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)