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

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)