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

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)