75a416f1986c367ecb24c355c1f50399ba262684
[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 <flash/nand.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' found", p->device->name);
151 }
152 else if (retval == ERROR_NAND_OPERATION_FAILED)
153 {
154 command_print(CMD_CTX, "probing failed for NAND flash device");
155 }
156 else
157 {
158 command_print(CMD_CTX, "unknown error when probing NAND flash device");
159 }
160
161 return ERROR_OK;
162 }
163
164 COMMAND_HANDLER(handle_nand_erase_command)
165 {
166 if (CMD_ARGC != 1 && CMD_ARGC != 3)
167 {
168 return ERROR_COMMAND_SYNTAX_ERROR;
169
170 }
171
172 struct nand_device *p;
173 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
174 if (ERROR_OK != retval)
175 return retval;
176
177 unsigned long offset;
178 unsigned long length;
179
180 /* erase specified part of the chip; or else everything */
181 if (CMD_ARGC == 3) {
182 unsigned long size = p->erase_size * p->num_blocks;
183
184 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
185 if ((offset % p->erase_size) != 0 || offset >= size)
186 return ERROR_INVALID_ARGUMENTS;
187
188 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
189 if ((length == 0) || (length % p->erase_size) != 0
190 || (length + offset) > size)
191 return ERROR_INVALID_ARGUMENTS;
192
193 offset /= p->erase_size;
194 length /= p->erase_size;
195 } else {
196 offset = 0;
197 length = p->num_blocks;
198 }
199
200 retval = nand_erase(p, offset, offset + length - 1);
201 if (retval == ERROR_OK)
202 {
203 command_print(CMD_CTX, "erased blocks %lu to %lu "
204 "on NAND flash device #%s '%s'",
205 offset, offset + length,
206 CMD_ARGV[0], p->device->name);
207 }
208 else if (retval == ERROR_NAND_OPERATION_FAILED)
209 {
210 command_print(CMD_CTX, "erase failed");
211 }
212 else
213 {
214 command_print(CMD_CTX, "unknown error when erasing NAND flash device");
215 }
216
217 return ERROR_OK;
218 }
219
220 COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
221 {
222 int first = -1;
223 int last = -1;
224
225 if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
226 {
227 return ERROR_COMMAND_SYNTAX_ERROR;
228
229 }
230
231 struct nand_device *p;
232 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
233 if (ERROR_OK != retval)
234 return retval;
235
236 if (CMD_ARGC == 3)
237 {
238 unsigned long offset;
239 unsigned long length;
240
241 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
242 if (offset % p->erase_size)
243 return ERROR_INVALID_ARGUMENTS;
244 offset /= p->erase_size;
245
246 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
247 if (length % p->erase_size)
248 return ERROR_INVALID_ARGUMENTS;
249
250 length -= 1;
251 length /= p->erase_size;
252
253 first = offset;
254 last = offset + length;
255 }
256
257 retval = nand_build_bbt(p, first, last);
258 if (retval == ERROR_OK)
259 {
260 command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
261 "use \"nand info\" command to list blocks");
262 }
263 else if (retval == ERROR_NAND_OPERATION_FAILED)
264 {
265 command_print(CMD_CTX, "error when checking for bad blocks on "
266 "NAND flash device");
267 }
268 else
269 {
270 command_print(CMD_CTX, "unknown error when checking for bad "
271 "blocks on NAND flash device");
272 }
273
274 return ERROR_OK;
275 }
276
277 COMMAND_HANDLER(handle_nand_write_command)
278 {
279 struct nand_device *nand = NULL;
280 struct nand_fileio_state s;
281 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
282 &s, &nand, FILEIO_READ, false, true);
283 if (ERROR_OK != retval)
284 return retval;
285
286 uint32_t total_bytes = s.size;
287 while (s.size > 0)
288 {
289 int bytes_read = nand_fileio_read(nand, &s);
290 if (bytes_read <= 0)
291 {
292 command_print(CMD_CTX, "error while reading file");
293 return nand_fileio_cleanup(&s);
294 }
295 s.size -= bytes_read;
296
297 retval = nand_write_page(nand, s.address / nand->page_size,
298 s.page, s.page_size, s.oob, s.oob_size);
299 if (ERROR_OK != retval)
300 {
301 command_print(CMD_CTX, "failed writing file %s "
302 "to NAND flash %s at offset 0x%8.8" PRIx32,
303 CMD_ARGV[1], CMD_ARGV[0], s.address);
304 return nand_fileio_cleanup(&s);
305 }
306 s.address += s.page_size;
307 }
308
309 if (nand_fileio_finish(&s))
310 {
311 command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
312 "offset 0x%8.8" PRIx32 " in %fs (%0.3f kb/s)",
313 CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
314 duration_kbps(&s.bench, total_bytes));
315 }
316 return ERROR_OK;
317 }
318
319 COMMAND_HANDLER(handle_nand_verify_command)
320 {
321 struct nand_device *nand = NULL;
322 struct nand_fileio_state file;
323 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
324 &file, &nand, FILEIO_READ, false, true);
325 if (ERROR_OK != retval)
326 return retval;
327
328 struct nand_fileio_state dev;
329 nand_fileio_init(&dev);
330 dev.address = file.address;
331 dev.size = file.size;
332 dev.oob_format = file.oob_format;
333 retval = nand_fileio_start(CMD_CTX, nand, NULL, FILEIO_NONE, &dev);
334 if (ERROR_OK != retval)
335 return retval;
336
337 while (file.size > 0)
338 {
339 int retval = nand_read_page(nand, dev.address / dev.page_size,
340 dev.page, dev.page_size, dev.oob, dev.oob_size);
341 if (ERROR_OK != retval)
342 {
343 command_print(CMD_CTX, "reading NAND flash page failed");
344 nand_fileio_cleanup(&dev);
345 return nand_fileio_cleanup(&file);
346 }
347
348 int bytes_read = nand_fileio_read(nand, &file);
349 if (bytes_read <= 0)
350 {
351 command_print(CMD_CTX, "error while reading file");
352 nand_fileio_cleanup(&dev);
353 return nand_fileio_cleanup(&file);
354 }
355
356 if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
357 (dev.oob && memcmp(dev.oob, file.oob, dev.oob_size)) )
358 {
359 command_print(CMD_CTX, "NAND flash contents differ "
360 "at 0x%8.8" PRIx32, dev.address);
361 nand_fileio_cleanup(&dev);
362 return nand_fileio_cleanup(&file);
363 }
364
365 file.size -= bytes_read;
366 dev.address += nand->page_size;
367 }
368
369 if (nand_fileio_finish(&file) == ERROR_OK)
370 {
371 command_print(CMD_CTX, "verified file %s in NAND flash %s "
372 "up to offset 0x%8.8" PRIx32 " in %fs (%0.3f kb/s)",
373 CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
374 duration_kbps(&file.bench, dev.size));
375 }
376
377 return nand_fileio_cleanup(&dev);
378 }
379
380 COMMAND_HANDLER(handle_nand_dump_command)
381 {
382 struct nand_device *nand = NULL;
383 struct nand_fileio_state s;
384 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
385 &s, &nand, FILEIO_WRITE, true, false);
386 if (ERROR_OK != retval)
387 return retval;
388
389 while (s.size > 0)
390 {
391 size_t size_written;
392 int retval = nand_read_page(nand, s.address / nand->page_size,
393 s.page, s.page_size, s.oob, s.oob_size);
394 if (ERROR_OK != retval)
395 {
396 command_print(CMD_CTX, "reading NAND flash page failed");
397 return nand_fileio_cleanup(&s);
398 }
399
400 if (NULL != s.page)
401 fileio_write(&s.fileio, s.page_size, s.page, &size_written);
402
403 if (NULL != s.oob)
404 fileio_write(&s.fileio, s.oob_size, s.oob, &size_written);
405
406 s.size -= nand->page_size;
407 s.address += nand->page_size;
408 }
409
410 if (nand_fileio_finish(&s) == ERROR_OK)
411 {
412 command_print(CMD_CTX, "dumped %zu bytes in %fs (%0.3f kb/s)",
413 s.fileio.size, duration_elapsed(&s.bench),
414 duration_kbps(&s.bench, s.fileio.size));
415 }
416 return ERROR_OK;
417 }
418
419 COMMAND_HANDLER(handle_nand_raw_access_command)
420 {
421 if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
422 {
423 return ERROR_COMMAND_SYNTAX_ERROR;
424 }
425
426 struct nand_device *p;
427 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
428 if (ERROR_OK != retval)
429 return retval;
430
431 if (NULL == p->device)
432 {
433 command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
434 return ERROR_OK;
435 }
436
437 if (CMD_ARGC == 2)
438 COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw);
439
440 const char *msg = p->use_raw ? "enabled" : "disabled";
441 command_print(CMD_CTX, "raw access is %s", msg);
442
443 return ERROR_OK;
444 }
445
446 static const struct command_registration nand_exec_command_handlers[] = {
447 {
448 .name = "list",
449 .handler = &handle_nand_list_command,
450 .mode = COMMAND_EXEC,
451 .help = "list configured NAND flash devices",
452 },
453 {
454 .name = "info",
455 .handler = &handle_nand_info_command,
456 .mode = COMMAND_EXEC,
457 .usage = "<bank>",
458 .help = "print info about a NAND flash device",
459 },
460 {
461 .name = "probe",
462 .handler = &handle_nand_probe_command,
463 .mode = COMMAND_EXEC,
464 .usage = "<bank>",
465 .help = "identify NAND flash device <num>",
466
467 },
468 {
469 .name = "check_bad_blocks",
470 .handler = &handle_nand_check_bad_blocks_command,
471 .mode = COMMAND_EXEC,
472 .usage = "<bank> [<offset> <length>]",
473 .help = "check NAND flash device <num> for bad blocks",
474 },
475 {
476 .name = "erase",
477 .handler = &handle_nand_erase_command,
478 .mode = COMMAND_EXEC,
479 .usage = "<bank> [<offset> <length>]",
480 .help = "erase blocks on NAND flash device",
481 },
482 {
483 .name = "dump",
484 .handler = &handle_nand_dump_command,
485 .mode = COMMAND_EXEC,
486 .usage = "<bank> <filename> <offset> <length> "
487 "[oob_raw | oob_only]",
488 .help = "dump from NAND flash device",
489 },
490 {
491 .name = "verify",
492 .handler = &handle_nand_verify_command,
493 .mode = COMMAND_EXEC,
494 .usage = "<bank> <filename> <offset> "
495 "[oob_raw | oob_only | oob_softecc | oob_softecc_kw]",
496 .help = "verify NAND flash device",
497 },
498 {
499 .name = "write",
500 .handler = &handle_nand_write_command,
501 .mode = COMMAND_EXEC,
502 .usage = "<bank> <filename> <offset> "
503 "[oob_raw | oob_only | oob_softecc | oob_softecc_kw]",
504 .help = "write to NAND flash device",
505 },
506 {
507 .name = "raw_access",
508 .handler = &handle_nand_raw_access_command,
509 .mode = COMMAND_EXEC,
510 .usage = "<num> ['enable'|'disable']",
511 .help = "raw access to NAND flash device",
512 },
513 COMMAND_REGISTRATION_DONE
514 };
515
516 int nand_init(struct command_context *cmd_ctx)
517 {
518 if (!nand_devices)
519 return ERROR_OK;
520 struct command *parent = command_find_in_context(cmd_ctx, "nand");
521 return register_commands(cmd_ctx, parent, nand_exec_command_handlers);
522 }
523
524 COMMAND_HANDLER(handle_nand_init_command)
525 {
526 if (CMD_ARGC != 0)
527 return ERROR_COMMAND_SYNTAX_ERROR;
528
529 static bool nand_initialized = false;
530 if (nand_initialized)
531 {
532 LOG_INFO("'nand init' has already been called");
533 return ERROR_OK;
534 }
535 nand_initialized = true;
536
537 LOG_DEBUG("Initializing NAND devices...");
538 return nand_init(CMD_CTX);
539 }
540 int nand_list_walker(struct nand_flash_controller *c, void *x)
541 {
542 struct command_context *cmd_ctx = (struct command_context *)x;
543 command_print(cmd_ctx, " %s", c->name);
544 return ERROR_OK;
545 }
546 COMMAND_HANDLER(handle_nand_list_drivers)
547 {
548 command_print(CMD_CTX, "Available NAND flash controller drivers:");
549 return nand_driver_walk(&nand_list_walker, CMD_CTX);
550 }
551
552 static COMMAND_HELPER(create_nand_device, const char *bank_name,
553 struct nand_flash_controller *controller)
554 {
555 if (NULL != controller->commands)
556 {
557 int retval = register_commands(CMD_CTX, NULL,
558 controller->commands);
559 if (ERROR_OK != retval)
560 return retval;
561 }
562 struct nand_device *c = malloc(sizeof(struct nand_device));
563
564 c->name = strdup(bank_name);
565 c->controller = controller;
566 c->controller_priv = NULL;
567 c->manufacturer = NULL;
568 c->device = NULL;
569 c->bus_width = 0;
570 c->address_cycles = 0;
571 c->page_size = 0;
572 c->use_raw = 0;
573 c->next = NULL;
574
575 int retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
576 if (ERROR_OK != retval)
577 {
578 LOG_ERROR("'%s' driver rejected nand flash", controller->name);
579 free(c);
580 return ERROR_OK;
581 }
582
583 return ERROR_OK;
584 }
585
586 COMMAND_HANDLER(handle_nand_device_command)
587 {
588 if (CMD_ARGC < 1)
589 {
590 LOG_ERROR("incomplete nand device configuration");
591 return ERROR_FLASH_BANK_INVALID;
592 }
593
594 // save name and increment (for compatibility) with drivers
595 const char *bank_name = *CMD_ARGV++;
596 CMD_ARGC--;
597
598 const char *driver_name = CMD_ARGV[0];
599 struct nand_flash_controller *controller;
600 controller = nand_driver_find_by_name(CMD_ARGV[0]);
601 if (NULL == controller)
602 {
603 LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
604 return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
605 }
606 return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller);
607 }
608
609 static const struct command_registration nand_config_command_handlers[] = {
610 {
611 .name = "device",
612 .handler = &handle_nand_device_command,
613 .mode = COMMAND_CONFIG,
614 .help = "defines a new NAND bank",
615 },
616 {
617 .name = "drivers",
618 .handler = &handle_nand_list_drivers,
619 .mode = COMMAND_ANY,
620 .help = "lists available NAND drivers",
621 },
622 {
623 .name = "init",
624 .mode = COMMAND_CONFIG,
625 .handler = &handle_nand_init_command,
626 .help = "initialize NAND devices",
627 },
628 COMMAND_REGISTRATION_DONE
629 };
630 static const struct command_registration nand_command_handlers[] = {
631 {
632 .name = "nand",
633 .mode = COMMAND_ANY,
634 .help = "NAND flash command group",
635 .chain = nand_config_command_handlers,
636 },
637 COMMAND_REGISTRATION_DONE
638 };
639
640 int nand_register_commands(struct command_context *cmd_ctx)
641 {
642 return register_commands(cmd_ctx, NULL, nand_command_handlers);
643 }
644
645

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)