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

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)