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