7b848880db7373e282aef1fd6dcfbca24488af6a
[openocd.git] / src / flash / nand / tcl.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
4 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
5 * *
6 * Partially based on drivers/mtd/nand_ids.c from Linux. *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "core.h"
28 #include "imp.h"
29 #include "fileio.h"
30
31 // to be removed
32 extern struct nand_device *nand_devices;
33
34 COMMAND_HANDLER(handle_nand_list_command)
35 {
36 struct nand_device *p;
37 int i;
38
39 if (!nand_devices)
40 {
41 command_print(CMD_CTX, "no NAND flash devices configured");
42 return ERROR_OK;
43 }
44
45 for (p = nand_devices, i = 0; p; p = p->next, i++)
46 {
47 if (p->device)
48 command_print(CMD_CTX, "#%i: %s (%s) "
49 "pagesize: %i, buswidth: %i,\n\t"
50 "blocksize: %i, blocks: %i",
51 i, p->device->name, p->manufacturer->name,
52 p->page_size, p->bus_width,
53 p->erase_size, p->num_blocks);
54 else
55 command_print(CMD_CTX, "#%i: not probed", i);
56 }
57
58 return ERROR_OK;
59 }
60
61 COMMAND_HANDLER(handle_nand_info_command)
62 {
63 int i = 0;
64 int j = 0;
65 int first = -1;
66 int last = -1;
67
68 switch (CMD_ARGC) {
69 default:
70 return ERROR_COMMAND_SYNTAX_ERROR;
71 case 1:
72 first = 0;
73 last = INT32_MAX;
74 break;
75 case 2:
76 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i);
77 first = last = i;
78 i = 0;
79 break;
80 case 3:
81 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
82 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
83 break;
84 }
85
86 struct nand_device *p;
87 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
88 if (ERROR_OK != retval)
89 return retval;
90
91 if (NULL == p->device)
92 {
93 command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
94 return ERROR_OK;
95 }
96
97 if (first >= p->num_blocks)
98 first = p->num_blocks - 1;
99
100 if (last >= p->num_blocks)
101 last = p->num_blocks - 1;
102
103 command_print(CMD_CTX, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
104 i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
105
106 for (j = first; j <= last; j++)
107 {
108 char *erase_state, *bad_state;
109
110 if (p->blocks[j].is_erased == 0)
111 erase_state = "not erased";
112 else if (p->blocks[j].is_erased == 1)
113 erase_state = "erased";
114 else
115 erase_state = "erase state unknown";
116
117 if (p->blocks[j].is_bad == 0)
118 bad_state = "";
119 else if (p->blocks[j].is_bad == 1)
120 bad_state = " (marked bad)";
121 else
122 bad_state = " (block condition unknown)";
123
124 command_print(CMD_CTX,
125 "\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s",
126 j,
127 p->blocks[j].offset,
128 p->blocks[j].size / 1024,
129 erase_state,
130 bad_state);
131 }
132
133 return ERROR_OK;
134 }
135
136 COMMAND_HANDLER(handle_nand_probe_command)
137 {
138 if (CMD_ARGC != 1)
139 {
140 return ERROR_COMMAND_SYNTAX_ERROR;
141 }
142
143 struct nand_device *p;
144 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
145 if (ERROR_OK != retval)
146 return retval;
147
148 if ((retval = nand_probe(p)) == ERROR_OK)
149 {
150 command_print(CMD_CTX, "NAND flash device '%s (%s)' found",
151 p->device->name, p->manufacturer->name);
152 }
153 else if (retval == ERROR_NAND_OPERATION_FAILED)
154 {
155 command_print(CMD_CTX, "probing failed for NAND flash device");
156 }
157 else
158 {
159 command_print(CMD_CTX, "unknown error when probing NAND flash device");
160 }
161
162 return ERROR_OK;
163 }
164
165 COMMAND_HANDLER(handle_nand_erase_command)
166 {
167 if (CMD_ARGC != 1 && CMD_ARGC != 3)
168 {
169 return ERROR_COMMAND_SYNTAX_ERROR;
170
171 }
172
173 struct nand_device *p;
174 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
175 if (ERROR_OK != retval)
176 return retval;
177
178 unsigned long offset;
179 unsigned long length;
180
181 /* erase specified part of the chip; or else everything */
182 if (CMD_ARGC == 3) {
183 unsigned long size = p->erase_size * p->num_blocks;
184
185 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
186 if ((offset % p->erase_size) != 0 || offset >= size)
187 return ERROR_INVALID_ARGUMENTS;
188
189 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
190 if ((length == 0) || (length % p->erase_size) != 0
191 || (length + offset) > size)
192 return ERROR_INVALID_ARGUMENTS;
193
194 offset /= p->erase_size;
195 length /= p->erase_size;
196 } else {
197 offset = 0;
198 length = p->num_blocks;
199 }
200
201 retval = nand_erase(p, offset, offset + length - 1);
202 if (retval == ERROR_OK)
203 {
204 command_print(CMD_CTX, "erased blocks %lu to %lu "
205 "on NAND flash device #%s '%s'",
206 offset, offset + length,
207 CMD_ARGV[0], p->device->name);
208 }
209 else if (retval == ERROR_NAND_OPERATION_FAILED)
210 {
211 command_print(CMD_CTX, "erase failed");
212 }
213 else
214 {
215 command_print(CMD_CTX, "unknown error when erasing NAND flash device");
216 }
217
218 return ERROR_OK;
219 }
220
221 COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
222 {
223 int first = -1;
224 int last = -1;
225
226 if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
227 {
228 return ERROR_COMMAND_SYNTAX_ERROR;
229
230 }
231
232 struct nand_device *p;
233 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
234 if (ERROR_OK != retval)
235 return retval;
236
237 if (CMD_ARGC == 3)
238 {
239 unsigned long offset;
240 unsigned long length;
241
242 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
243 if (offset % p->erase_size)
244 return ERROR_INVALID_ARGUMENTS;
245 offset /= p->erase_size;
246
247 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
248 if (length % p->erase_size)
249 return ERROR_INVALID_ARGUMENTS;
250
251 length -= 1;
252 length /= p->erase_size;
253
254 first = offset;
255 last = offset + length;
256 }
257
258 retval = nand_build_bbt(p, first, last);
259 if (retval == ERROR_OK)
260 {
261 command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
262 "use \"nand info\" command to list blocks");
263 }
264 else if (retval == ERROR_NAND_OPERATION_FAILED)
265 {
266 command_print(CMD_CTX, "error when checking for bad blocks on "
267 "NAND flash device");
268 }
269 else
270 {
271 command_print(CMD_CTX, "unknown error when checking for bad "
272 "blocks on NAND flash device");
273 }
274
275 return ERROR_OK;
276 }
277
278 COMMAND_HANDLER(handle_nand_write_command)
279 {
280 struct nand_device *nand = NULL;
281 struct nand_fileio_state s;
282 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
283 &s, &nand, FILEIO_READ, false, true);
284 if (ERROR_OK != retval)
285 return retval;
286
287 uint32_t total_bytes = s.size;
288 while (s.size > 0)
289 {
290 int bytes_read = nand_fileio_read(nand, &s);
291 if (bytes_read <= 0)
292 {
293 command_print(CMD_CTX, "error while reading file");
294 return nand_fileio_cleanup(&s);
295 }
296 s.size -= bytes_read;
297
298 retval = nand_write_page(nand, s.address / nand->page_size,
299 s.page, s.page_size, s.oob, s.oob_size);
300 if (ERROR_OK != retval)
301 {
302 command_print(CMD_CTX, "failed writing file %s "
303 "to NAND flash %s at offset 0x%8.8" PRIx32,
304 CMD_ARGV[1], CMD_ARGV[0], s.address);
305 return nand_fileio_cleanup(&s);
306 }
307 s.address += s.page_size;
308 }
309
310 if (nand_fileio_finish(&s))
311 {
312 command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
313 "offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
314 CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
315 duration_kbps(&s.bench, total_bytes));
316 }
317 return ERROR_OK;
318 }
319
320 COMMAND_HANDLER(handle_nand_verify_command)
321 {
322 struct nand_device *nand = NULL;
323 struct nand_fileio_state file;
324 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
325 &file, &nand, FILEIO_READ, false, true);
326 if (ERROR_OK != retval)
327 return retval;
328
329 struct nand_fileio_state dev;
330 nand_fileio_init(&dev);
331 dev.address = file.address;
332 dev.size = file.size;
333 dev.oob_format = file.oob_format;
334 retval = nand_fileio_start(CMD_CTX, nand, NULL, FILEIO_NONE, &dev);
335 if (ERROR_OK != retval)
336 return retval;
337
338 while (file.size > 0)
339 {
340 retval = nand_read_page(nand, dev.address / dev.page_size,
341 dev.page, dev.page_size, dev.oob, dev.oob_size);
342 if (ERROR_OK != retval)
343 {
344 command_print(CMD_CTX, "reading NAND flash page failed");
345 nand_fileio_cleanup(&dev);
346 nand_fileio_cleanup(&file);
347 return retval;
348 }
349
350 int bytes_read = nand_fileio_read(nand, &file);
351 if (bytes_read <= 0)
352 {
353 command_print(CMD_CTX, "error while reading file");
354 nand_fileio_cleanup(&dev);
355 nand_fileio_cleanup(&file);
356 return ERROR_FAIL;
357 }
358
359 if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
360 (dev.oob && memcmp(dev.oob, file.oob, dev.oob_size)) )
361 {
362 command_print(CMD_CTX, "NAND flash contents differ "
363 "at 0x%8.8" PRIx32, dev.address);
364 nand_fileio_cleanup(&dev);
365 nand_fileio_cleanup(&file);
366 return ERROR_FAIL;
367 }
368
369 file.size -= bytes_read;
370 dev.address += nand->page_size;
371 }
372
373 if (nand_fileio_finish(&file) == ERROR_OK)
374 {
375 command_print(CMD_CTX, "verified file %s in NAND flash %s "
376 "up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
377 CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
378 duration_kbps(&file.bench, dev.size));
379 }
380
381 return nand_fileio_cleanup(&dev);
382 }
383
384 COMMAND_HANDLER(handle_nand_dump_command)
385 {
386 struct nand_device *nand = NULL;
387 struct nand_fileio_state s;
388 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
389 &s, &nand, FILEIO_WRITE, true, false);
390 if (ERROR_OK != retval)
391 return retval;
392
393 while (s.size > 0)
394 {
395 size_t size_written;
396 retval = nand_read_page(nand, s.address / nand->page_size,
397 s.page, s.page_size, s.oob, s.oob_size);
398 if (ERROR_OK != retval)
399 {
400 command_print(CMD_CTX, "reading NAND flash page failed");
401 nand_fileio_cleanup(&s);
402 return retval;
403 }
404
405 if (NULL != s.page)
406 fileio_write(&s.fileio, s.page_size, s.page, &size_written);
407
408 if (NULL != s.oob)
409 fileio_write(&s.fileio, s.oob_size, s.oob, &size_written);
410
411 s.size -= nand->page_size;
412 s.address += nand->page_size;
413 }
414
415 if (nand_fileio_finish(&s) == ERROR_OK)
416 {
417 command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)",
418 (long)s.fileio.size, duration_elapsed(&s.bench),
419 duration_kbps(&s.bench, s.fileio.size));
420 }
421 return ERROR_OK;
422 }
423
424 COMMAND_HANDLER(handle_nand_raw_access_command)
425 {
426 if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
427 {
428 return ERROR_COMMAND_SYNTAX_ERROR;
429 }
430
431 struct nand_device *p;
432 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
433 if (ERROR_OK != retval)
434 return retval;
435
436 if (NULL == p->device)
437 {
438 command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
439 return ERROR_OK;
440 }
441
442 if (CMD_ARGC == 2)
443 COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw);
444
445 const char *msg = p->use_raw ? "enabled" : "disabled";
446 command_print(CMD_CTX, "raw access is %s", msg);
447
448 return ERROR_OK;
449 }
450
451 static const struct command_registration nand_exec_command_handlers[] = {
452 {
453 .name = "list",
454 .handler = handle_nand_list_command,
455 .mode = COMMAND_EXEC,
456 .help = "list configured NAND flash devices",
457 },
458 {
459 .name = "info",
460 .handler = handle_nand_info_command,
461 .mode = COMMAND_EXEC,
462 .usage = "[banknum | first_bank_num last_bank_num]",
463 .help = "print info about one or more NAND flash devices",
464 },
465 {
466 .name = "probe",
467 .handler = handle_nand_probe_command,
468 .mode = COMMAND_EXEC,
469 .usage = "bank_id",
470 .help = "identify NAND flash device",
471 },
472 {
473 .name = "check_bad_blocks",
474 .handler = handle_nand_check_bad_blocks_command,
475 .mode = COMMAND_EXEC,
476 .usage = "bank_id [offset length]",
477 .help = "check all or part of NAND flash device for bad blocks",
478 },
479 {
480 .name = "erase",
481 .handler = handle_nand_erase_command,
482 .mode = COMMAND_EXEC,
483 .usage = "bank_id [offset length]",
484 .help = "erase all or subset of blocks on NAND flash device",
485 },
486 {
487 .name = "dump",
488 .handler = handle_nand_dump_command,
489 .mode = COMMAND_EXEC,
490 .usage = "bank_id filename offset length "
491 "['oob_raw'|'oob_only']",
492 .help = "dump from NAND flash device",
493 },
494 {
495 .name = "verify",
496 .handler = handle_nand_verify_command,
497 .mode = COMMAND_EXEC,
498 .usage = "bank_id filename offset "
499 "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
500 .help = "verify NAND flash device",
501 },
502 {
503 .name = "write",
504 .handler = handle_nand_write_command,
505 .mode = COMMAND_EXEC,
506 .usage = "bank_id filename offset "
507 "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
508 .help = "write to NAND flash device",
509 },
510 {
511 .name = "raw_access",
512 .handler = handle_nand_raw_access_command,
513 .mode = COMMAND_EXEC,
514 .usage = "bank_id ['enable'|'disable']",
515 .help = "raw access to NAND flash device",
516 },
517 COMMAND_REGISTRATION_DONE
518 };
519
520 static int nand_init(struct command_context *cmd_ctx)
521 {
522 if (!nand_devices)
523 return ERROR_OK;
524 struct command *parent = command_find_in_context(cmd_ctx, "nand");
525 return register_commands(cmd_ctx, parent, nand_exec_command_handlers);
526 }
527
528 COMMAND_HANDLER(handle_nand_init_command)
529 {
530 if (CMD_ARGC != 0)
531 return ERROR_COMMAND_SYNTAX_ERROR;
532
533 static bool nand_initialized = false;
534 if (nand_initialized)
535 {
536 LOG_INFO("'nand init' has already been called");
537 return ERROR_OK;
538 }
539 nand_initialized = true;
540
541 LOG_DEBUG("Initializing NAND devices...");
542 return nand_init(CMD_CTX);
543 }
544
545 static int nand_list_walker(struct nand_flash_controller *c, void *x)
546 {
547 struct command_context *cmd_ctx = (struct command_context *)x;
548 command_print(cmd_ctx, " %s", c->name);
549 return ERROR_OK;
550 }
551
552 COMMAND_HANDLER(handle_nand_list_drivers)
553 {
554 command_print(CMD_CTX, "Available NAND flash controller drivers:");
555 return nand_driver_walk(&nand_list_walker, CMD_CTX);
556 }
557
558 static COMMAND_HELPER(create_nand_device, const char *bank_name,
559 struct nand_flash_controller *controller)
560 {
561 if (NULL != controller->commands)
562 {
563 int retval = register_commands(CMD_CTX, NULL,
564 controller->commands);
565 if (ERROR_OK != retval)
566 return retval;
567 }
568 struct nand_device *c = malloc(sizeof(struct nand_device));
569
570 c->name = strdup(bank_name);
571 c->controller = controller;
572 c->controller_priv = NULL;
573 c->manufacturer = NULL;
574 c->device = NULL;
575 c->bus_width = 0;
576 c->address_cycles = 0;
577 c->page_size = 0;
578 c->use_raw = 0;
579 c->next = NULL;
580
581 int retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
582 if (ERROR_OK != retval)
583 {
584 LOG_ERROR("'%s' driver rejected nand flash", controller->name);
585 free(c);
586 return ERROR_OK;
587 }
588
589 nand_device_add(c);
590
591 return ERROR_OK;
592 }
593
594 COMMAND_HANDLER(handle_nand_device_command)
595 {
596 if (CMD_ARGC < 1)
597 {
598 LOG_ERROR("incomplete nand device configuration");
599 return ERROR_FLASH_BANK_INVALID;
600 }
601
602 // save name and increment (for compatibility) with drivers
603 const char *bank_name = *CMD_ARGV++;
604 CMD_ARGC--;
605
606 const char *driver_name = CMD_ARGV[0];
607 struct nand_flash_controller *controller;
608 controller = nand_driver_find_by_name(CMD_ARGV[0]);
609 if (NULL == controller)
610 {
611 LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
612 return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
613 }
614 return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller);
615 }
616
617 static const struct command_registration nand_config_command_handlers[] = {
618 {
619 .name = "device",
620 .handler = &handle_nand_device_command,
621 .mode = COMMAND_CONFIG,
622 .help = "defines a new NAND bank",
623 .usage = "bank_id driver target [driver_options ...]",
624 },
625 {
626 .name = "drivers",
627 .handler = &handle_nand_list_drivers,
628 .mode = COMMAND_ANY,
629 .help = "lists available NAND drivers",
630 },
631 {
632 .name = "init",
633 .mode = COMMAND_CONFIG,
634 .handler = &handle_nand_init_command,
635 .help = "initialize NAND devices",
636 },
637 COMMAND_REGISTRATION_DONE
638 };
639 static const struct command_registration nand_command_handlers[] = {
640 {
641 .name = "nand",
642 .mode = COMMAND_ANY,
643 .help = "NAND flash command group",
644 .chain = nand_config_command_handlers,
645 },
646 COMMAND_REGISTRATION_DONE
647 };
648
649 int nand_register_commands(struct command_context *cmd_ctx)
650 {
651 return register_commands(cmd_ctx, NULL, nand_command_handlers);
652 }
653
654

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)