blob: 274ef0b99383f05241ad6b091b575640d0ab8c4e [file] [log] [blame]
wdenkdc7c9a12003-03-26 06:55:25 +00001/*
2 * Driver for NAND support, Rick Bronson
3 * borrowed heavily from:
4 * (c) 1999 Machine Vision Holdings, Inc.
5 * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
wdenk384cc682005-04-03 22:35:21 +00006 *
7 * Added 16-bit nand support
8 * (C) 2004 Texas Instruments
wdenkdc7c9a12003-03-26 06:55:25 +00009 */
10
11#include <common.h>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010012
13
14#ifndef CFG_NAND_LEGACY
15/*
16 *
17 * New NAND support
18 *
19 */
20#include <common.h>
21
22#if (CONFIG_COMMANDS & CFG_CMD_NAND)
23
24#include <command.h>
25#include <watchdog.h>
26#include <malloc.h>
27#include <asm/byteorder.h>
28
29#ifdef CONFIG_SHOW_BOOT_PROGRESS
30# include <status_led.h>
31# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
32#else
33# define SHOW_BOOT_PROGRESS(arg)
34#endif
35
36#include <jffs2/jffs2.h>
37#include <nand.h>
38
39extern nand_info_t nand_info[]; /* info for NAND chips */
40
41static int nand_dump_oob(nand_info_t *nand, ulong off)
42{
43 return 0;
44}
45
46static int nand_dump(nand_info_t *nand, ulong off)
47{
48 int i;
49 u_char *buf, *p;
50
51 buf = malloc(nand->oobblock + nand->oobsize);
52 if (!buf) {
53 puts("No memory for page buffer\n");
54 return 1;
55 }
56 off &= ~(nand->oobblock - 1);
57 i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
58 if (i < 0) {
59 printf("Error (%d) reading page %08x\n", i, off);
60 free(buf);
61 return 1;
62 }
63 printf("Page %08x dump:\n", off);
64 i = nand->oobblock >> 4; p = buf;
65 while (i--) {
66 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
67 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
68 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
69 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
70 p += 16;
71 }
72 puts("OOB:\n");
73 i = nand->oobsize >> 3;
74 while (i--) {
75 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
76 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
77 p += 8;
78 }
79 free(buf);
80
81 return 0;
82}
83
84/* ------------------------------------------------------------------------- */
85
86static void
87arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize)
88{
89 *off = 0;
90 *size = 0;
91
92#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART)
93 if (argc >= 1 && strcmp(argv[0], "partition") == 0) {
94 int part_num;
95 struct part_info *part;
96 const char *partstr;
97
98 if (argc >= 2)
99 partstr = argv[1];
100 else
101 partstr = getenv("partition");
102
103 if (partstr)
104 part_num = (int)simple_strtoul(partstr, NULL, 10);
105 else
106 part_num = 0;
107
108 part = jffs2_part_info(part_num);
109 if (part == NULL) {
110 printf("\nInvalid partition %d\n", part_num);
111 return;
112 }
113 *size = part->size;
114 *off = (ulong)part->offset;
115 } else
116#endif
117 {
118 if (argc >= 1)
119 *off = (ulong)simple_strtoul(argv[0], NULL, 16);
120 else
121 *off = 0;
122
123 if (argc >= 2)
124 *size = (ulong)simple_strtoul(argv[1], NULL, 16);
125 else
126 *size = totsize - *off;
127
128 }
129
130}
131
132int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
133{
134 int i, dev, ret;
135 ulong addr, off, size;
136 char *cmd, *s;
137 nand_info_t *nand;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200138 int quiet = 0;
139 const char *quiet_str = getenv("quiet");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100140
141 /* at least two arguments please */
142 if (argc < 2)
143 goto usage;
144
Stefan Roese2255b2d2006-10-10 12:36:02 +0200145 if (quiet_str)
146 quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
147
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100148 cmd = argv[1];
149
150 if (strcmp(cmd, "info") == 0) {
151
152 putc('\n');
153 for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
154 if (nand_info[i].name)
155 printf("Device %d: %s, sector size %lu KiB\n",
156 i, nand_info[i].name,
157 nand_info[i].erasesize >> 10);
158 }
159 return 0;
160 }
161
162 if (strcmp(cmd, "device") == 0) {
163
164 if (argc < 3) {
165 if ((nand_curr_device < 0) ||
166 (nand_curr_device >= CFG_MAX_NAND_DEVICE))
167 puts("\nno devices available\n");
168 else
169 printf("\nDevice %d: %s\n", nand_curr_device,
170 nand_info[nand_curr_device].name);
171 return 0;
172 }
173 dev = (int)simple_strtoul(argv[2], NULL, 10);
174 if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
175 puts("No such device\n");
176 return 1;
177 }
178 printf("Device %d: %s", dev, nand_info[dev].name);
179 puts("... is now current device\n");
180 nand_curr_device = dev;
181 return 0;
182 }
183
184 if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
185 strncmp(cmd, "dump", 4) != 0 &&
Stefan Roese2255b2d2006-10-10 12:36:02 +0200186 strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
187 strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
188 strcmp(cmd, "biterr") != 0 &&
189 strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100190 goto usage;
191
192 /* the following commands operate on the current device */
193 if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
194 !nand_info[nand_curr_device].name) {
195 puts("\nno devices available\n");
196 return 1;
197 }
198 nand = &nand_info[nand_curr_device];
199
200 if (strcmp(cmd, "bad") == 0) {
201 printf("\nDevice %d bad blocks:\n", nand_curr_device);
202 for (off = 0; off < nand->size; off += nand->erasesize)
203 if (nand_block_isbad(nand, off))
204 printf(" %08x\n", off);
205 return 0;
206 }
207
Stefan Roese2255b2d2006-10-10 12:36:02 +0200208 if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
209 nand_erase_options_t opts;
210 int clean = argc >= 3 && !strcmp("clean", argv[2]);
211 int rest_argc = argc - 2;
212 char **rest_argv = argv + 2;
213 int scrub = !strcmp(cmd, "scrub");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100214
Stefan Roese2255b2d2006-10-10 12:36:02 +0200215 if (clean) {
216 rest_argc--;
217 rest_argv++;
218 }
219
220 if (rest_argc == 0) {
221
222 printf("\nNAND %s: device %d whole chip\n",
223 cmd,
224 nand_curr_device);
225
226 off = size = 0;
227 } else {
228 arg_off_size(rest_argc, rest_argv, &off, &size,
229 nand->size);
230
231 if (off == 0 && size == 0)
232 return 1;
233
234 printf("\nNAND %s: device %d offset 0x%x, size 0x%x\n",
235 cmd, nand_curr_device, off, size);
236 }
237
238 memset(&opts, 0, sizeof(opts));
239 opts.offset = off;
240 opts.length = size;
241 opts.jffs2 = clean;
242 opts.quiet = quiet;
243
244 if (scrub) {
245 printf("Warning: "
246 "scrub option will erase all factory set "
247 "bad blocks!\n"
248 " "
249 "There is no reliable way to recover them.\n"
250 " "
251 "Use this command only for testing purposes "
252 "if you\n"
253 " "
254 "are shure of what you are doing!\n"
255 "\nReally scrub this NAND flash? <y/N>\n"
256 );
257
258 if (getc() == 'y' && getc() == '\r') {
259 opts.scrub = 1;
260 } else {
261 printf("scrub aborted\n");
262 return -1;
263 }
264 }
265 ret = nand_erase_opts(nand, &opts);
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100266 printf("%s\n", ret ? "ERROR" : "OK");
267
268 return ret == 0 ? 0 : 1;
269 }
270
271 if (strncmp(cmd, "dump", 4) == 0) {
272 if (argc < 3)
273 goto usage;
274
275 s = strchr(cmd, '.');
276 off = (int)simple_strtoul(argv[2], NULL, 16);
277
278 if (s != NULL && strcmp(s, ".oob") == 0)
279 ret = nand_dump_oob(nand, off);
280 else
281 ret = nand_dump(nand, off);
282
283 return ret == 0 ? 1 : 0;
284
285 }
286
287 /* read write */
288 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200289 int read;
290
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100291 if (argc < 4)
292 goto usage;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200293
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100294 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
295
296 arg_off_size(argc - 3, argv + 3, &off, &size, nand->size);
297 if (off == 0 && size == 0)
298 return 1;
299
Stefan Roese2255b2d2006-10-10 12:36:02 +0200300 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100301 printf("\nNAND %s: device %d offset %u, size %u ... ",
Stefan Roese2255b2d2006-10-10 12:36:02 +0200302 read ? "read" : "write", nand_curr_device, off, size);
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100303
Stefan Roese2255b2d2006-10-10 12:36:02 +0200304 s = strchr(cmd, '.');
305 if (s != NULL &&
306 (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
307 if (read) {
308 /* read */
309 nand_read_options_t opts;
310 memset(&opts, 0, sizeof(opts));
311 opts.buffer = (u_char*) addr;
312 opts.length = size;
313 opts.offset = off;
314 opts.quiet = quiet;
315 ret = nand_read_opts(nand, &opts);
316 } else {
317 /* write */
318 nand_write_options_t opts;
319 memset(&opts, 0, sizeof(opts));
320 opts.buffer = (u_char*) addr;
321 opts.length = size;
322 opts.offset = off;
323 /* opts.forcejffs2 = 1; */
324 opts.pad = 1;
325 opts.blockalign = 1;
326 opts.quiet = quiet;
327 ret = nand_write_opts(nand, &opts);
328 }
329 printf("%s\n", ret ? "ERROR" : "OK");
330 return ret == 0 ? 0 : 1;
331 }
332
333 if (read)
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100334 ret = nand_read(nand, off, &size, (u_char *)addr);
335 else
336 ret = nand_write(nand, off, &size, (u_char *)addr);
337
338 printf(" %d bytes %s: %s\n", size,
Stefan Roese2255b2d2006-10-10 12:36:02 +0200339 read ? "read" : "written", ret ? "ERROR" : "OK");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100340
341 return ret == 0 ? 0 : 1;
342 }
Stefan Roese2255b2d2006-10-10 12:36:02 +0200343
344 /* 2006-09-28 gc: implement missing commands */
345 if (strcmp(cmd, "markbad") == 0) {
346 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
347
348 int ret = nand->block_markbad(nand, addr);
349 if (ret == 0) {
350 printf("block 0x%08lx successfully marked as bad\n",
351 (ulong) addr);
352 return 0;
353 } else {
354 printf("block 0x%08lx NOT marked as bad! ERROR %d\n",
355 (ulong) addr, ret);
356 }
357 return 1;
358 }
359 if (strcmp(cmd, "biterr") == 0) {
360 /* todo */
361 return 1;
362 }
363
364 if (strcmp(cmd, "lock") == 0) {
365 int tight = 0;
366 int status = 0;
367 if (argc == 3) {
368 if (!strcmp("tight", argv[2]))
369 tight = 1;
370 if (!strcmp("status", argv[2]))
371 status = 1;
372 }
373
374 if (status) {
375 ulong block_start = 0;
376 ulong off;
377 int last_status = -1;
378
379 struct nand_chip *nand_chip = nand->priv;
380 /* check the WP bit */
381 nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);
382 printf("device is %swrite protected\n",
383 (nand_chip->read_byte(nand) & 0x80 ?
384 "NOT " : "" ) );
385
386 for (off = 0; off < nand->size; off += nand->oobblock) {
387 int s = nand_get_lock_status(nand, off);
388
389 /* print message only if status has changed
390 * or at end of chip
391 */
392 if (off == nand->size - nand->oobblock
393 || (s != last_status && off != 0)) {
394
395 printf("%08x - %08x: %8d pages %s%s%s\n",
396 block_start,
397 off-1,
398 (off-block_start)/nand->oobblock,
399 ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
400 ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
401 ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
402 }
403
404 last_status = s;
405 }
406 } else {
407 if (!nand_lock(nand, tight)) {
408 printf ("NAND flash successfully locked\n");
409 } else {
410 printf ("Error locking NAND flash. \n");
411 return 1;
412 }
413 }
414 return 0;
415 }
416
417 if (strcmp(cmd, "unlock") == 0) {
418 if (argc == 2) {
419 off = 0;
420 size = nand->size;
421 } else {
422 arg_off_size(argc - 2, argv + 2, &off, &size,
423 nand->size);
424 }
425
426 if (!nand_unlock(nand, off, size)) {
427 printf("NAND flash successfully unlocked\n");
428 } else {
429 printf("Error unlocking NAND flash. "
430 "Write and erase will probably fail\n");
431 return 1;
432 }
433 return 0;
434 }
435
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100436usage:
437 printf("Usage:\n%s\n", cmdtp->usage);
438 return 1;
439}
440
441U_BOOT_CMD(nand, 5, 1, do_nand,
442 "nand - NAND sub-system\n",
443 "info - show available NAND devices\n"
444 "nand device [dev] - show or set current device\n"
445 "nand read[.jffs2] - addr off size\n"
446 "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n"
447 " at offset `off' to/from memory address `addr'\n"
448 "nand erase [clean] [off size] - erase `size' bytes from\n"
449 " offset `off' (entire device if not specified)\n"
450 "nand bad - show bad blocks\n"
451 "nand dump[.oob] off - dump page\n"
452 "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
453 "nand markbad off - mark bad block at offset (UNSAFE)\n"
Stefan Roese2255b2d2006-10-10 12:36:02 +0200454 "nand biterr off - make a bit error at offset (UNSAFE)\n"
455 "nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
456 "nand unlock [offset] [size] - unlock section\n");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100457
458int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
459{
460 char *boot_device = NULL;
461 char *ep;
462 int dev;
463 int r;
464 ulong addr, cnt, offset = 0;
465 image_header_t *hdr;
466 nand_info_t *nand;
467
468 switch (argc) {
469 case 1:
470 addr = CFG_LOAD_ADDR;
471 boot_device = getenv("bootdevice");
472 break;
473 case 2:
474 addr = simple_strtoul(argv[1], NULL, 16);
475 boot_device = getenv("bootdevice");
476 break;
477 case 3:
478 addr = simple_strtoul(argv[1], NULL, 16);
479 boot_device = argv[2];
480 break;
481 case 4:
482 addr = simple_strtoul(argv[1], NULL, 16);
483 boot_device = argv[2];
484 offset = simple_strtoul(argv[3], NULL, 16);
485 break;
486 default:
487 printf("Usage:\n%s\n", cmdtp->usage);
488 SHOW_BOOT_PROGRESS(-1);
489 return 1;
490 }
491
492 if (!boot_device) {
493 puts("\n** No boot device **\n");
494 SHOW_BOOT_PROGRESS(-1);
495 return 1;
496 }
497
498 dev = simple_strtoul(boot_device, &ep, 16);
499
500 if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
501 printf("\n** Device %d not available\n", dev);
502 SHOW_BOOT_PROGRESS(-1);
503 return 1;
504 }
505
506 nand = &nand_info[dev];
507 printf("\nLoading from device %d: %s (offset 0x%lx)\n",
508 dev, nand->name, offset);
509
510 cnt = nand->oobblock;
511 r = nand_read(nand, offset, &cnt, (u_char *) addr);
512 if (r) {
513 printf("** Read error on %d\n", dev);
514 SHOW_BOOT_PROGRESS(-1);
515 return 1;
516 }
517
518 hdr = (image_header_t *) addr;
519
520 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
521 printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
522 SHOW_BOOT_PROGRESS(-1);
523 return 1;
524 }
525
526 print_image_hdr(hdr);
527
528 cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t));
529
530 r = nand_read(nand, offset, &cnt, (u_char *) addr);
531 if (r) {
532 printf("** Read error on %d\n", dev);
533 SHOW_BOOT_PROGRESS(-1);
534 return 1;
535 }
536
537 /* Loading ok, update default load address */
538
539 load_addr = addr;
540
541 /* Check if we should attempt an auto-start */
542 if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
543 char *local_args[2];
544 extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
545
546 local_args[0] = argv[0];
547 local_args[1] = NULL;
548
549 printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
550
551 do_bootm(cmdtp, 0, 1, local_args);
552 return 1;
553 }
554 return 0;
555}
556
557U_BOOT_CMD(nboot, 4, 1, do_nandboot,
558 "nboot - boot from NAND device\n", "loadAddr dev\n");
559
560
561#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
562
563#else /* CFG_NAND_LEGACY */
564/*
565 *
566 * Legacy NAND support - to be phased out
567 *
568 */
wdenkdc7c9a12003-03-26 06:55:25 +0000569#include <command.h>
570#include <malloc.h>
571#include <asm/io.h>
wdenka3d991b2004-04-15 21:48:45 +0000572#include <watchdog.h>
wdenkdc7c9a12003-03-26 06:55:25 +0000573
574#ifdef CONFIG_SHOW_BOOT_PROGRESS
575# include <status_led.h>
576# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
577#else
578# define SHOW_BOOT_PROGRESS(arg)
579#endif
580
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100581#if (CONFIG_COMMANDS & CFG_CMD_NAND)
582#include <linux/mtd/nand_legacy.h>
583#if 0
wdenkdc7c9a12003-03-26 06:55:25 +0000584#include <linux/mtd/nand_ids.h>
wdenk7a8e9bed2003-05-31 18:35:21 +0000585#include <jffs2/jffs2.h>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100586#endif
wdenkdc7c9a12003-03-26 06:55:25 +0000587
wdenk1f4bb372003-07-27 00:21:01 +0000588#ifdef CONFIG_OMAP1510
589void archflashwp(void *archdata, int wp);
590#endif
591
592#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
593
wdenka43278a2003-09-11 19:48:06 +0000594#undef NAND_DEBUG
wdenkdc7c9a12003-03-26 06:55:25 +0000595#undef PSYCHO_DEBUG
wdenk7a8e9bed2003-05-31 18:35:21 +0000596
597/* ****************** WARNING *********************
598 * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
599 * erase (or at least attempt to erase) blocks that are marked
600 * bad. This can be very handy if you are _sure_ that the block
601 * is OK, say because you marked a good block bad to test bad
602 * block handling and you are done testing, or if you have
603 * accidentally marked blocks bad.
604 *
605 * Erasing factory marked bad blocks is a _bad_ idea. If the
606 * erase succeeds there is no reliable way to find them again,
607 * and attempting to program or erase bad blocks can affect
608 * the data in _other_ (good) blocks.
609 */
610#define ALLOW_ERASE_BAD_DEBUG 0
wdenkdc7c9a12003-03-26 06:55:25 +0000611
612#define CONFIG_MTD_NAND_ECC /* enable ECC */
wdenk1f4bb372003-07-27 00:21:01 +0000613#define CONFIG_MTD_NAND_ECC_JFFS2
wdenkdc7c9a12003-03-26 06:55:25 +0000614
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100615/* bits for nand_legacy_rw() `cmd'; or together as needed */
wdenk7a8e9bed2003-05-31 18:35:21 +0000616#define NANDRW_READ 0x01
617#define NANDRW_WRITE 0x00
618#define NANDRW_JFFS2 0x02
wdenka3d991b2004-04-15 21:48:45 +0000619#define NANDRW_JFFS2_SKIP 0x04
wdenk7a8e9bed2003-05-31 18:35:21 +0000620
wdenkdc7c9a12003-03-26 06:55:25 +0000621/*
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100622 * Imports from nand_legacy.c
wdenkdc7c9a12003-03-26 06:55:25 +0000623 */
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100624extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
625extern int curr_device;
626extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,
627 size_t len, int clean);
628extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,
629 size_t len, size_t *retlen, u_char *buf);
630extern void nand_print(struct nand_chip *nand);
631extern void nand_print_bad(struct nand_chip *nand);
632extern int nand_read_oob(struct nand_chip *nand, size_t ofs,
633 size_t len, size_t *retlen, u_char *buf);
634extern int nand_write_oob(struct nand_chip *nand, size_t ofs,
635 size_t len, size_t *retlen, const u_char *buf);
wdenkdc7c9a12003-03-26 06:55:25 +0000636
wdenkdc7c9a12003-03-26 06:55:25 +0000637
638int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
639{
640 int rcode = 0;
641
642 switch (argc) {
643 case 0:
644 case 1:
645 printf ("Usage:\n%s\n", cmdtp->usage);
646 return 1;
647 case 2:
wdenk8bde7f72003-06-27 21:31:46 +0000648 if (strcmp(argv[1],"info") == 0) {
wdenkdc7c9a12003-03-26 06:55:25 +0000649 int i;
650
651 putc ('\n');
652
653 for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) {
654 if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN)
655 continue; /* list only known devices */
656 printf ("Device %d: ", i);
657 nand_print(&nand_dev_desc[i]);
658 }
659 return 0;
660
661 } else if (strcmp(argv[1],"device") == 0) {
662 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
663 puts ("\nno devices available\n");
664 return 1;
665 }
666 printf ("\nDevice %d: ", curr_device);
667 nand_print(&nand_dev_desc[curr_device]);
668 return 0;
wdenk7a8e9bed2003-05-31 18:35:21 +0000669
670 } else if (strcmp(argv[1],"bad") == 0) {
671 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
672 puts ("\nno devices available\n");
673 return 1;
674 }
675 printf ("\nDevice %d bad blocks:\n", curr_device);
676 nand_print_bad(&nand_dev_desc[curr_device]);
677 return 0;
678
wdenkdc7c9a12003-03-26 06:55:25 +0000679 }
680 printf ("Usage:\n%s\n", cmdtp->usage);
681 return 1;
682 case 3:
683 if (strcmp(argv[1],"device") == 0) {
684 int dev = (int)simple_strtoul(argv[2], NULL, 10);
685
686 printf ("\nDevice %d: ", dev);
687 if (dev >= CFG_MAX_NAND_DEVICE) {
688 puts ("unknown device\n");
689 return 1;
690 }
691 nand_print(&nand_dev_desc[dev]);
692 /*nand_print (dev);*/
693
694 if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
695 return 1;
696 }
697
698 curr_device = dev;
699
700 puts ("... is now current device\n");
701
702 return 0;
703 }
wdenk7a8e9bed2003-05-31 18:35:21 +0000704 else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) {
705 struct nand_chip* nand = &nand_dev_desc[curr_device];
706 ulong off = 0;
707 ulong size = nand->totlen;
708 int ret;
709
710 printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
711 curr_device, off, size);
712
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100713 ret = nand_legacy_erase (nand, off, size, 1);
wdenk7a8e9bed2003-05-31 18:35:21 +0000714
715 printf("%s\n", ret ? "ERROR" : "OK");
716
717 return ret;
718 }
wdenkdc7c9a12003-03-26 06:55:25 +0000719
720 printf ("Usage:\n%s\n", cmdtp->usage);
721 return 1;
722 default:
723 /* at least 4 args */
724
wdenk7a8e9bed2003-05-31 18:35:21 +0000725 if (strncmp(argv[1], "read", 4) == 0 ||
726 strncmp(argv[1], "write", 5) == 0) {
wdenkdc7c9a12003-03-26 06:55:25 +0000727 ulong addr = simple_strtoul(argv[2], NULL, 16);
728 ulong off = simple_strtoul(argv[3], NULL, 16);
729 ulong size = simple_strtoul(argv[4], NULL, 16);
wdenk7a8e9bed2003-05-31 18:35:21 +0000730 int cmd = (strncmp(argv[1], "read", 4) == 0) ?
731 NANDRW_READ : NANDRW_WRITE;
wdenkdc7c9a12003-03-26 06:55:25 +0000732 int ret, total;
wdenk7a8e9bed2003-05-31 18:35:21 +0000733 char* cmdtail = strchr(argv[1], '.');
734
735 if (cmdtail && !strncmp(cmdtail, ".oob", 2)) {
736 /* read out-of-band data */
737 if (cmd & NANDRW_READ) {
738 ret = nand_read_oob(nand_dev_desc + curr_device,
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200739 off, size, (size_t *)&total,
wdenk7a8e9bed2003-05-31 18:35:21 +0000740 (u_char*)addr);
741 }
742 else {
743 ret = nand_write_oob(nand_dev_desc + curr_device,
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200744 off, size, (size_t *)&total,
wdenk7a8e9bed2003-05-31 18:35:21 +0000745 (u_char*)addr);
746 }
747 return ret;
748 }
749 else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2))
750 cmd |= NANDRW_JFFS2; /* skip bad blocks */
wdenka3d991b2004-04-15 21:48:45 +0000751 else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) {
752 cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
753 if (cmd & NANDRW_READ)
754 cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
755 }
wdenk7a8e9bed2003-05-31 18:35:21 +0000756#ifdef SXNI855T
757 /* need ".e" same as ".j" for compatibility with older units */
758 else if (cmdtail && !strcmp(cmdtail, ".e"))
759 cmd |= NANDRW_JFFS2; /* skip bad blocks */
760#endif
stroesea842a6d2004-12-16 17:45:46 +0000761#ifdef CFG_NAND_SKIP_BAD_DOT_I
762 /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
763 /* ".i" for image -> read skips bad block (no 0xff) */
Stefan Roese9bcf2ab2005-08-12 16:46:35 +0200764 else if (cmdtail && !strcmp(cmdtail, ".i")) {
stroesea842a6d2004-12-16 17:45:46 +0000765 cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
766 if (cmd & NANDRW_READ)
767 cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
Stefan Roese9bcf2ab2005-08-12 16:46:35 +0200768 }
stroesea842a6d2004-12-16 17:45:46 +0000769#endif /* CFG_NAND_SKIP_BAD_DOT_I */
wdenk7a8e9bed2003-05-31 18:35:21 +0000770 else if (cmdtail) {
771 printf ("Usage:\n%s\n", cmdtp->usage);
772 return 1;
773 }
wdenkdc7c9a12003-03-26 06:55:25 +0000774
Stefan Roese2255b2d2006-10-10 12:36:02 +0200775 printf ("\nNAND %s: device %d offset %ld, size %ld ...\n",
wdenk7a8e9bed2003-05-31 18:35:21 +0000776 (cmd & NANDRW_READ) ? "read" : "write",
777 curr_device, off, size);
wdenkdc7c9a12003-03-26 06:55:25 +0000778
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100779 ret = nand_legacy_rw(nand_dev_desc + curr_device, cmd, off, size,
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200780 (size_t *)&total, (u_char*)addr);
wdenkdc7c9a12003-03-26 06:55:25 +0000781
wdenk1f4bb372003-07-27 00:21:01 +0000782 printf (" %d bytes %s: %s\n", total,
wdenk998eaae2004-04-18 19:43:36 +0000783 (cmd & NANDRW_READ) ? "read" : "written",
wdenkdc7c9a12003-03-26 06:55:25 +0000784 ret ? "ERROR" : "OK");
785
786 return ret;
wdenk7a8e9bed2003-05-31 18:35:21 +0000787 } else if (strcmp(argv[1],"erase") == 0 &&
788 (argc == 4 || strcmp("clean", argv[2]) == 0)) {
789 int clean = argc == 5;
790 ulong off = simple_strtoul(argv[2 + clean], NULL, 16);
791 ulong size = simple_strtoul(argv[3 + clean], NULL, 16);
wdenkdc7c9a12003-03-26 06:55:25 +0000792 int ret;
793
Stefan Roese2255b2d2006-10-10 12:36:02 +0200794 printf ("\nNAND erase: device %d offset %ld, size %ld ...\n",
wdenkdc7c9a12003-03-26 06:55:25 +0000795 curr_device, off, size);
796
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100797 ret = nand_legacy_erase (nand_dev_desc + curr_device,
798 off, size, clean);
wdenkdc7c9a12003-03-26 06:55:25 +0000799
800 printf("%s\n", ret ? "ERROR" : "OK");
801
802 return ret;
803 } else {
804 printf ("Usage:\n%s\n", cmdtp->usage);
805 rcode = 1;
806 }
807
808 return rcode;
809 }
810}
811
wdenk0d498392003-07-01 21:06:45 +0000812U_BOOT_CMD(
813 nand, 5, 1, do_nand,
Stefan Roese2255b2d2006-10-10 12:36:02 +0200814 "nand - legacy NAND sub-system\n",
wdenkb0fce992003-06-29 21:03:46 +0000815 "info - show available NAND devices\n"
816 "nand device [dev] - show or set current device\n"
wdenka3d991b2004-04-15 21:48:45 +0000817 "nand read[.jffs2[s]] addr off size\n"
wdenkb0fce992003-06-29 21:03:46 +0000818 "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
819 " at offset `off' to/from memory address `addr'\n"
820 "nand erase [clean] [off size] - erase `size' bytes from\n"
821 " offset `off' (entire device if not specified)\n"
822 "nand bad - show bad blocks\n"
823 "nand read.oob addr off size - read out-of-band data\n"
824 "nand write.oob addr off size - read out-of-band data\n"
825);
826
wdenkdc7c9a12003-03-26 06:55:25 +0000827int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
828{
829 char *boot_device = NULL;
830 char *ep;
831 int dev;
832 ulong cnt;
833 ulong addr;
834 ulong offset = 0;
835 image_header_t *hdr;
836 int rcode = 0;
837 switch (argc) {
838 case 1:
839 addr = CFG_LOAD_ADDR;
840 boot_device = getenv ("bootdevice");
841 break;
842 case 2:
843 addr = simple_strtoul(argv[1], NULL, 16);
844 boot_device = getenv ("bootdevice");
845 break;
846 case 3:
847 addr = simple_strtoul(argv[1], NULL, 16);
848 boot_device = argv[2];
849 break;
850 case 4:
851 addr = simple_strtoul(argv[1], NULL, 16);
852 boot_device = argv[2];
853 offset = simple_strtoul(argv[3], NULL, 16);
854 break;
855 default:
856 printf ("Usage:\n%s\n", cmdtp->usage);
857 SHOW_BOOT_PROGRESS (-1);
858 return 1;
859 }
860
861 if (!boot_device) {
862 puts ("\n** No boot device **\n");
863 SHOW_BOOT_PROGRESS (-1);
864 return 1;
865 }
866
867 dev = simple_strtoul(boot_device, &ep, 16);
868
869 if ((dev >= CFG_MAX_NAND_DEVICE) ||
870 (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {
871 printf ("\n** Device %d not available\n", dev);
872 SHOW_BOOT_PROGRESS (-1);
873 return 1;
874 }
875
wdenk7a8e9bed2003-05-31 18:35:21 +0000876 printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
wdenkdc7c9a12003-03-26 06:55:25 +0000877 dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
878 offset);
879
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100880 if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset,
881 SECTORSIZE, NULL, (u_char *)addr)) {
wdenkdc7c9a12003-03-26 06:55:25 +0000882 printf ("** Read error on %d\n", dev);
883 SHOW_BOOT_PROGRESS (-1);
884 return 1;
885 }
886
887 hdr = (image_header_t *)addr;
888
889 if (ntohl(hdr->ih_magic) == IH_MAGIC) {
890
891 print_image_hdr (hdr);
892
893 cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
894 cnt -= SECTORSIZE;
895 } else {
Wolfgang Denkdc013d42006-03-12 01:59:35 +0100896 printf ("\n** Bad Magic Number 0x%x **\n", ntohl(hdr->ih_magic));
wdenkdc7c9a12003-03-26 06:55:25 +0000897 SHOW_BOOT_PROGRESS (-1);
898 return 1;
899 }
900
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100901 if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ,
902 offset + SECTORSIZE, cnt, NULL,
903 (u_char *)(addr+SECTORSIZE))) {
wdenkdc7c9a12003-03-26 06:55:25 +0000904 printf ("** Read error on %d\n", dev);
905 SHOW_BOOT_PROGRESS (-1);
906 return 1;
907 }
908
909 /* Loading ok, update default load address */
910
911 load_addr = addr;
912
913 /* Check if we should attempt an auto-start */
914 if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
915 char *local_args[2];
916 extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
917
918 local_args[0] = argv[0];
919 local_args[1] = NULL;
920
wdenk7a8e9bed2003-05-31 18:35:21 +0000921 printf ("Automatic boot of image at addr 0x%08lx ...\n", addr);
wdenkdc7c9a12003-03-26 06:55:25 +0000922
923 do_bootm (cmdtp, 0, 1, local_args);
924 rcode = 1;
925 }
926 return rcode;
927}
928
wdenk0d498392003-07-01 21:06:45 +0000929U_BOOT_CMD(
930 nboot, 4, 1, do_nandboot,
wdenkb0fce992003-06-29 21:03:46 +0000931 "nboot - boot from NAND device\n",
932 "loadAddr dev\n"
933);
934
wdenkdc7c9a12003-03-26 06:55:25 +0000935#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100936
937#endif /* CFG_NAND_LEGACY */