cmd_nand.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /*
  2. * Rick Bronson and Pantelis Antoniou
  3. */
  4. #include <common.h>
  5. #if (CONFIG_COMMANDS & CFG_CMD_NAND)
  6. #include <command.h>
  7. #include <watchdog.h>
  8. #include <malloc.h>
  9. #include <asm/byteorder.h>
  10. #ifdef CONFIG_SHOW_BOOT_PROGRESS
  11. # include <status_led.h>
  12. # define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
  13. #else
  14. # define SHOW_BOOT_PROGRESS(arg)
  15. #endif
  16. #include <jffs2/jffs2.h>
  17. #include <nand.h>
  18. extern nand_info_t nand_info[]; /* info for NAND chips */
  19. static int nand_dump_oob(nand_info_t *nand, ulong off)
  20. {
  21. return 0;
  22. }
  23. static int nand_dump(nand_info_t *nand, ulong off)
  24. {
  25. int i;
  26. u_char *buf, *p;
  27. buf = malloc(nand->oobblock + nand->oobsize);
  28. if (!buf) {
  29. puts("No memory for page buffer\n");
  30. return 1;
  31. }
  32. off &= ~(nand->oobblock - 1);
  33. i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
  34. if (i < 0) {
  35. printf("Error (%d) reading page %08x\n", i, off);
  36. free(buf);
  37. return 1;
  38. }
  39. printf("Page %08x dump:\n", off);
  40. i = nand->oobblock >> 4; p = buf;
  41. while (i--) {
  42. printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
  43. " %02x %02x %02x %02x %02x %02x %02x %02x\n",
  44. p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  45. p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
  46. p += 16;
  47. }
  48. puts("OOB:\n");
  49. i = nand->oobsize >> 3;
  50. while (i--) {
  51. printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
  52. p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
  53. p += 8;
  54. }
  55. free(buf);
  56. return 0;
  57. }
  58. /* ------------------------------------------------------------------------- */
  59. static void
  60. arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize)
  61. {
  62. *off = 0;
  63. *size = 0;
  64. #if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART)
  65. if (argc >= 1 && strcmp(argv[0], "partition") == 0) {
  66. int part_num;
  67. struct part_info *part;
  68. const char *partstr;
  69. if (argc >= 2)
  70. partstr = argv[1];
  71. else
  72. partstr = getenv("partition");
  73. if (partstr)
  74. part_num = (int)simple_strtoul(partstr, NULL, 10);
  75. else
  76. part_num = 0;
  77. part = jffs2_part_info(part_num);
  78. if (part == NULL) {
  79. printf("\nInvalid partition %d\n", part_num);
  80. return;
  81. }
  82. *size = part->size;
  83. *off = (ulong)part->offset;
  84. } else
  85. #endif
  86. {
  87. if (argc >= 1)
  88. *off = (ulong)simple_strtoul(argv[0], NULL, 16);
  89. else
  90. *off = 0;
  91. if (argc >= 2)
  92. *size = (ulong)simple_strtoul(argv[1], NULL, 16);
  93. else
  94. *size = totsize - *off;
  95. }
  96. }
  97. int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
  98. {
  99. int i, dev, ret;
  100. ulong addr, off, size;
  101. char *cmd, *s;
  102. nand_info_t *nand;
  103. /* at least two arguments please */
  104. if (argc < 2)
  105. goto usage;
  106. cmd = argv[1];
  107. if (strcmp(cmd, "info") == 0) {
  108. putc('\n');
  109. for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
  110. if (nand_info[i].name)
  111. printf("Device %d: %s\n", i, nand_info[i].name);
  112. }
  113. return 0;
  114. }
  115. if (strcmp(cmd, "device") == 0) {
  116. if (argc < 3) {
  117. if ((nand_curr_device < 0) ||
  118. (nand_curr_device >= CFG_MAX_NAND_DEVICE))
  119. puts("\nno devices available\n");
  120. else
  121. printf("\nDevice %d: %s\n", nand_curr_device,
  122. nand_info[nand_curr_device].name);
  123. return 0;
  124. }
  125. dev = (int)simple_strtoul(argv[2], NULL, 10);
  126. if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
  127. puts("No such device\n");
  128. return 1;
  129. }
  130. printf("Device %d: %s", dev, nand_info[dev].name);
  131. puts("... is now current device\n");
  132. nand_curr_device = dev;
  133. return 0;
  134. }
  135. if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
  136. strncmp(cmd, "dump", 4) != 0 &&
  137. strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0
  138. #ifdef CONFIG_MTD_NAND_UNSAFE
  139. && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "biterr") != 0
  140. && strcmp(cmd, "markbad") != 0
  141. #endif
  142. )
  143. goto usage;
  144. /* the following commands operate on the current device */
  145. if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
  146. !nand_info[nand_curr_device].name) {
  147. puts("\nno devices available\n");
  148. return 1;
  149. }
  150. nand = &nand_info[nand_curr_device];
  151. if (strcmp(cmd, "bad") == 0) {
  152. printf("\nDevice %d bad blocks:\n", nand_curr_device);
  153. for (off = 0; off < nand->size; off += nand->erasesize)
  154. if (nand_block_isbad(nand, off))
  155. printf(" %08x\n", off);
  156. return 0;
  157. }
  158. if (strcmp(cmd, "erase") == 0
  159. #ifdef CONFIG_MTD_NAND_UNSAFE
  160. || strcmp(cmd, "scrub") == 0
  161. #endif
  162. ) {
  163. #ifdef CONFIG_MTD_NAND_UNSAFE
  164. i = strcmp(cmd, "scrub") == 0; /* 1 scrub, 0 = erase */
  165. #endif
  166. arg_off_size(argc - 2, argv + 2, &off, &size, nand->size);
  167. if (off == 0 && size == 0)
  168. return 1;
  169. printf("\nNAND %s: device %d offset 0x%x, size 0x%x ",
  170. #ifdef CONFIG_MTD_NAND_UNSAFE
  171. i ? "scrub" :
  172. #endif
  173. "erase",
  174. nand_curr_device, off, size);
  175. #ifdef CONFIG_MTD_NAND_UNSAFE
  176. if (i)
  177. ret = nand_scrub(nand, off, size);
  178. else
  179. #endif
  180. ret = nand_erase(nand, off, size);
  181. printf("%s\n", ret ? "ERROR" : "OK");
  182. return ret == 0 ? 0 : 1;
  183. }
  184. if (strncmp(cmd, "dump", 4) == 0) {
  185. if (argc < 3)
  186. goto usage;
  187. s = strchr(cmd, '.');
  188. off = (int)simple_strtoul(argv[2], NULL, 16);
  189. if (s != NULL && strcmp(s, ".oob") == 0)
  190. ret = nand_dump_oob(nand, off);
  191. else
  192. ret = nand_dump(nand, off);
  193. return ret == 0 ? 1 : 0;
  194. }
  195. /* read write */
  196. if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
  197. if (argc < 4)
  198. goto usage;
  199. /*
  200. s = strchr(cmd, '.');
  201. clean = CLEAN_NONE;
  202. if (s != NULL) {
  203. if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0
  204. || strcmp(s, ".i"))
  205. clean = CLEAN_JFFS2;
  206. }
  207. */
  208. addr = (ulong)simple_strtoul(argv[2], NULL, 16);
  209. arg_off_size(argc - 3, argv + 3, &off, &size, nand->size);
  210. if (off == 0 && size == 0)
  211. return 1;
  212. i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
  213. printf("\nNAND %s: device %d offset %u, size %u ... ",
  214. i ? "read" : "write", nand_curr_device, off, size);
  215. if (i)
  216. ret = nand_read(nand, off, &size, (u_char *)addr);
  217. else
  218. ret = nand_write(nand, off, &size, (u_char *)addr);
  219. printf(" %d bytes %s: %s\n", size,
  220. i ? "read" : "written", ret ? "ERROR" : "OK");
  221. return ret == 0 ? 0 : 1;
  222. }
  223. #ifdef CONFIG_MTD_NAND_UNSAFE
  224. if (strcmp(cmd, "markbad") == 0 || strcmp(cmd, "biterr") == 0) {
  225. if (argc < 3)
  226. goto usage;
  227. i = strcmp(cmd, "biterr") == 0;
  228. off = (int)simple_strtoul(argv[2], NULL, 16);
  229. if (i)
  230. ret = nand_make_bit_error(nand, off);
  231. else
  232. ret = nand_mark_bad(nand, off);
  233. return ret == 0 ? 0 : 1;
  234. }
  235. #endif
  236. usage:
  237. printf("Usage:\n%s\n", cmdtp->usage);
  238. return 1;
  239. }
  240. U_BOOT_CMD(nand, 5, 1, do_nand,
  241. "nand - NAND sub-system\n",
  242. "info - show available NAND devices\n"
  243. "nand device [dev] - show or set current device\n"
  244. "nand read[.jffs2] - addr off size\n"
  245. "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n"
  246. " at offset `off' to/from memory address `addr'\n"
  247. "nand erase [clean] [off size] - erase `size' bytes from\n"
  248. " offset `off' (entire device if not specified)\n"
  249. "nand bad - show bad blocks\n"
  250. "nand dump[.oob] off - dump page\n"
  251. "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
  252. "nand markbad off - mark bad block at offset (UNSAFE)\n"
  253. "nand biterr off - make a bit error at offset (UNSAFE)\n");
  254. int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
  255. {
  256. char *boot_device = NULL;
  257. char *ep;
  258. int dev;
  259. int r;
  260. ulong addr, cnt, offset = 0;
  261. image_header_t *hdr;
  262. nand_info_t *nand;
  263. switch (argc) {
  264. case 1:
  265. addr = CFG_LOAD_ADDR;
  266. boot_device = getenv("bootdevice");
  267. break;
  268. case 2:
  269. addr = simple_strtoul(argv[1], NULL, 16);
  270. boot_device = getenv("bootdevice");
  271. break;
  272. case 3:
  273. addr = simple_strtoul(argv[1], NULL, 16);
  274. boot_device = argv[2];
  275. break;
  276. case 4:
  277. addr = simple_strtoul(argv[1], NULL, 16);
  278. boot_device = argv[2];
  279. offset = simple_strtoul(argv[3], NULL, 16);
  280. break;
  281. default:
  282. printf("Usage:\n%s\n", cmdtp->usage);
  283. SHOW_BOOT_PROGRESS(-1);
  284. return 1;
  285. }
  286. if (!boot_device) {
  287. puts("\n** No boot device **\n");
  288. SHOW_BOOT_PROGRESS(-1);
  289. return 1;
  290. }
  291. dev = simple_strtoul(boot_device, &ep, 16);
  292. if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
  293. printf("\n** Device %d not available\n", dev);
  294. SHOW_BOOT_PROGRESS(-1);
  295. return 1;
  296. }
  297. nand = &nand_info[dev];
  298. printf("\nLoading from device %d: %s (offset 0x%lx)\n",
  299. dev, nand->name, offset);
  300. cnt = nand->oobblock;
  301. r = nand_read(nand, offset, &cnt, (u_char *) addr);
  302. if (r) {
  303. printf("** Read error on %d\n", dev);
  304. SHOW_BOOT_PROGRESS(-1);
  305. return 1;
  306. }
  307. hdr = (image_header_t *) addr;
  308. if (ntohl(hdr->ih_magic) != IH_MAGIC) {
  309. printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
  310. SHOW_BOOT_PROGRESS(-1);
  311. return 1;
  312. }
  313. print_image_hdr(hdr);
  314. cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t));
  315. r = nand_read(nand, offset, &cnt, (u_char *) addr);
  316. if (r) {
  317. printf("** Read error on %d\n", dev);
  318. SHOW_BOOT_PROGRESS(-1);
  319. return 1;
  320. }
  321. /* Loading ok, update default load address */
  322. load_addr = addr;
  323. /* Check if we should attempt an auto-start */
  324. if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
  325. char *local_args[2];
  326. extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
  327. local_args[0] = argv[0];
  328. local_args[1] = NULL;
  329. printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
  330. do_bootm(cmdtp, 0, 1, local_args);
  331. return 1;
  332. }
  333. return 0;
  334. }
  335. U_BOOT_CMD(nboot, 4, 1, do_nandboot,
  336. "nboot - boot from NAND device\n", "loadAddr dev\n");
  337. #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */