Commit ea533c260a801c4e51f92f75165cebe6d7b01e35

Authored by Scott Wood
1 parent f9a5254111

cmd_nand: some infrastructure fixes and refactoring

- If the current device is overridden by a named partition,
  - update the caller's pointer/index, rather than copy over the
    nand_info struct, and
  - be sure to call board_nand_select_device even when the device
    is overridden by a named partition.
- Support 64-bit offsets/sizes in a few more places.
- Refactor arg_off_size for added readability and flexibility,
  and some added checks such as partition size.
- Remove redundant check for bad subcommands -- if there's no match
  it'll print usage when it gets to the end anyway.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Tested-by: Ben Gardiner <bengardiner@nanometrics.ca>

Showing 1 changed file with 167 additions and 107 deletions Side-by-side Diff

... ... @@ -10,6 +10,13 @@
10 10 * (C) Copyright 2006-2007 OpenMoko, Inc.
11 11 * Added 16-bit nand support
12 12 * (C) 2004 Texas Instruments
  13 + *
  14 + * Copyright 2010 Freescale Semiconductor
  15 + * The portions of this file whose copyright is held by Freescale and which
  16 + * are not considered a derived work of GPL v2-only code may be distributed
  17 + * and/or modified under the terms of the GNU General Public License as
  18 + * published by the Free Software Foundation; either version 2 of the
  19 + * License, or (at your option) any later version.
13 20 */
14 21  
15 22 #include <common.h>
16 23  
17 24  
18 25  
19 26  
20 27  
21 28  
22 29  
23 30  
24 31  
25 32  
26 33  
27 34  
28 35  
29 36  
... ... @@ -85,74 +92,132 @@
85 92  
86 93 /* ------------------------------------------------------------------------- */
87 94  
88   -static inline int str2long(char *p, ulong *num)
  95 +static int set_dev(int dev)
89 96 {
  97 + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
  98 + !nand_info[dev].name) {
  99 + puts("No such device\n");
  100 + return -1;
  101 + }
  102 +
  103 + if (nand_curr_device == dev)
  104 + return 0;
  105 +
  106 + printf("Device %d: %s", dev, nand_info[dev].name);
  107 + puts("... is now current device\n");
  108 + nand_curr_device = dev;
  109 +
  110 +#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
  111 + board_nand_select_device(nand_info[dev].priv, dev);
  112 +#endif
  113 +
  114 + return 0;
  115 +}
  116 +
  117 +static inline int str2off(const char *p, loff_t *num)
  118 +{
90 119 char *endptr;
91 120  
  121 + *num = simple_strtoull(p, &endptr, 16);
  122 + return *p != '\0' && *endptr == '\0';
  123 +}
  124 +
  125 +static inline int str2long(const char *p, ulong *num)
  126 +{
  127 + char *endptr;
  128 +
92 129 *num = simple_strtoul(p, &endptr, 16);
93   - return (*p != '\0' && *endptr == '\0') ? 1 : 0;
  130 + return *p != '\0' && *endptr == '\0';
94 131 }
95 132  
96   -static int
97   -arg_off_size(int argc, char * const argv[], nand_info_t *nand, ulong *off, size_t *size)
  133 +static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)
98 134 {
99   - int idx = nand_curr_device;
100   -#if defined(CONFIG_CMD_MTDPARTS)
  135 +#ifdef CONFIG_CMD_MTDPARTS
101 136 struct mtd_device *dev;
102 137 struct part_info *part;
103 138 u8 pnum;
  139 + int ret;
104 140  
105   - if (argc >= 1 && !(str2long(argv[0], off))) {
106   - if ((mtdparts_init() == 0) &&
107   - (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) {
108   - if (dev->id->type != MTD_DEV_TYPE_NAND) {
109   - puts("not a NAND device\n");
110   - return -1;
111   - }
112   - *off = part->offset;
113   - if (argc >= 2) {
114   - if (!(str2long(argv[1], (ulong *)size))) {
115   - printf("'%s' is not a number\n", argv[1]);
116   - return -1;
117   - }
118   - if (*size > part->size)
119   - *size = part->size;
120   - } else {
121   - *size = part->size;
122   - }
123   - idx = dev->id->num;
124   - *nand = nand_info[idx];
125   - goto out;
126   - }
  141 + ret = mtdparts_init();
  142 + if (ret)
  143 + return ret;
  144 +
  145 + ret = find_dev_and_part(partname, &dev, &pnum, &part);
  146 + if (ret)
  147 + return ret;
  148 +
  149 + if (dev->id->type != MTD_DEV_TYPE_NAND) {
  150 + puts("not a NAND device\n");
  151 + return -1;
127 152 }
  153 +
  154 + *off = part->offset;
  155 + *size = part->size;
  156 + *idx = dev->id->num;
  157 +
  158 + ret = set_dev(*idx);
  159 + if (ret)
  160 + return ret;
  161 +
  162 + return 0;
  163 +#else
  164 + puts("offset is not a number\n");
  165 + return -1;
128 166 #endif
  167 +}
129 168  
130   - if (argc >= 1) {
131   - if (!(str2long(argv[0], off))) {
132   - printf("'%s' is not a number\n", argv[0]);
133   - return -1;
134   - }
135   - } else {
  169 +static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize)
  170 +{
  171 + if (!str2off(arg, off))
  172 + return get_part(arg, idx, off, maxsize);
  173 +
  174 + if (*off >= nand_info[*idx].size) {
  175 + puts("Offset exceeds device limit\n");
  176 + return -1;
  177 + }
  178 +
  179 + *maxsize = nand_info[*idx].size - *off;
  180 + return 0;
  181 +}
  182 +
  183 +static int arg_off_size(int argc, char *const argv[], int *idx,
  184 + loff_t *off, loff_t *size)
  185 +{
  186 + int ret;
  187 + loff_t maxsize;
  188 +
  189 + if (argc == 0) {
136 190 *off = 0;
  191 + *size = nand_info[*idx].size;
  192 + goto print;
137 193 }
138 194  
139   - if (argc >= 2) {
140   - if (!(str2long(argv[1], (ulong *)size))) {
141   - printf("'%s' is not a number\n", argv[1]);
142   - return -1;
143   - }
144   - } else {
145   - *size = nand->size - *off;
  195 + ret = arg_off(argv[0], idx, off, &maxsize);
  196 + if (ret)
  197 + return ret;
  198 +
  199 + if (argc == 1) {
  200 + *size = maxsize;
  201 + goto print;
146 202 }
147 203  
148   -#if defined(CONFIG_CMD_MTDPARTS)
149   -out:
150   -#endif
151   - printf("device %d ", idx);
152   - if (*size == nand->size)
  204 + if (!str2off(argv[1], size)) {
  205 + printf("'%s' is not a number\n", argv[1]);
  206 + return -1;
  207 + }
  208 +
  209 + if (*size > maxsize) {
  210 + puts("Size exceeds partition or device limit\n");
  211 + return -1;
  212 + }
  213 +
  214 +print:
  215 + printf("device %d ", *idx);
  216 + if (*size == nand_info[*idx].size)
153 217 puts("whole chip\n");
154 218 else
155   - printf("offset 0x%lx, size 0x%zx\n", *off, *size);
  219 + printf("offset 0x%llx, size 0x%llx\n",
  220 + (unsigned long long)*off, (unsigned long long)*size);
156 221 return 0;
157 222 }
158 223  
159 224  
160 225  
... ... @@ -200,14 +265,20 @@
200 265 #ifdef CONFIG_ENV_OFFSET_OOB
201 266 unsigned long nand_env_oob_offset;
202 267  
203   -int do_nand_env_oob(cmd_tbl_t *cmdtp, nand_info_t *nand,
204   - int argc, char * const argv[])
  268 +int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
205 269 {
206 270 int ret;
207 271 uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
208   -
  272 + nand_info_t *nand = &nand_info[0];
209 273 char *cmd = argv[1];
210 274  
  275 + if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !nand->name) {
  276 + puts("no devices available\n");
  277 + return 1;
  278 + }
  279 +
  280 + set_dev(0);
  281 +
211 282 if (!strcmp(cmd, "get")) {
212 283 ret = get_nand_env_oob(nand, &nand_env_oob_offset);
213 284 if (ret)
214 285  
215 286  
216 287  
... ... @@ -215,19 +286,24 @@
215 286  
216 287 printf("0x%08lx\n", nand_env_oob_offset);
217 288 } else if (!strcmp(cmd, "set")) {
218   - ulong addr;
219   - size_t dummy_size;
  289 + loff_t addr;
  290 + loff_t maxsize;
220 291 struct mtd_oob_ops ops;
  292 + int idx = 0;
221 293  
222 294 if (argc < 3)
223 295 goto usage;
224 296  
225   - if (arg_off_size(argc - 2, argv + 2, nand, &addr,
226   - &dummy_size) < 0) {
227   - printf("Offset or partition name expected\n");
  297 + if (arg_off(argv[2], &idx, &addr, &maxsize)) {
  298 + puts("Offset or partition name expected\n");
228 299 return 1;
229 300 }
230 301  
  302 + if (idx != 0) {
  303 + puts("Partition not on first NAND device\n");
  304 + return 1;
  305 + }
  306 +
231 307 if (nand->oobavail < ENV_OFFSET_SIZE) {
232 308 printf("Insufficient available OOB bytes:\n"
233 309 "%d OOB bytes available but %d required for "
... ... @@ -264,8 +340,8 @@
264 340  
265 341 if (addr != nand_env_oob_offset) {
266 342 printf("Verification of env offset in OOB failed: "
267   - "0x%08lx expected but got 0x%08lx\n",
268   - addr, nand_env_oob_offset);
  343 + "0x%08llx expected but got 0x%08lx\n",
  344 + (unsigned long long)addr, nand_env_oob_offset);
269 345 return 1;
270 346 }
271 347 } else {
... ... @@ -293,9 +369,9 @@
293 369  
294 370 int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
295 371 {
296   - int i, dev, ret = 0;
297   - ulong addr, off;
298   - size_t size;
  372 + int i, ret = 0;
  373 + ulong addr;
  374 + loff_t off, size;
299 375 char *cmd, *s;
300 376 nand_info_t *nand;
301 377 #ifdef CONFIG_SYS_NAND_QUIET
... ... @@ -304,6 +380,7 @@
304 380 int quiet = 0;
305 381 #endif
306 382 const char *quiet_str = getenv("quiet");
  383 + int dev = nand_curr_device;
307 384  
308 385 /* at least two arguments please */
309 386 if (argc < 2)
310 387  
311 388  
312 389  
313 390  
314 391  
315 392  
316 393  
317 394  
318 395  
319 396  
320 397  
321 398  
... ... @@ -325,68 +402,45 @@
325 402 }
326 403  
327 404 if (strcmp(cmd, "device") == 0) {
328   -
329 405 if (argc < 3) {
330 406 putc('\n');
331   - if ((nand_curr_device < 0) ||
332   - (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE))
  407 + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
333 408 puts("no devices available\n");
334 409 else
335   - nand_print_info(nand_curr_device);
  410 + nand_print_info(dev);
336 411 return 0;
337 412 }
  413 +
338 414 dev = (int)simple_strtoul(argv[2], NULL, 10);
339   - if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) {
340   - puts("No such device\n");
341   - return 1;
342   - }
343   - printf("Device %d: %s", dev, nand_info[dev].name);
344   - puts("... is now current device\n");
345   - nand_curr_device = dev;
  415 + set_dev(dev);
346 416  
347   -#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
348   - /*
349   - * Select the chip in the board/cpu specific driver
350   - */
351   - board_nand_select_device(nand_info[dev].priv, dev);
352   -#endif
353   -
354 417 return 0;
355 418 }
356 419  
357   - if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
358   - strncmp(cmd, "dump", 4) != 0 &&
359   - strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
360   - strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
361   - strcmp(cmd, "biterr") != 0 &&
362   - strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0
363 420 #ifdef CONFIG_ENV_OFFSET_OOB
364   - && strcmp(cmd, "env.oob") != 0
365   -#endif
366   - )
367   - goto usage;
368   -
369   -#ifdef CONFIG_ENV_OFFSET_OOB
370 421 /* this command operates only on the first nand device */
371   - if (strcmp(cmd, "env.oob") == 0) {
372   - return do_nand_env_oob(cmdtp, &nand_info[0],
373   - argc - 1, argv + 1);
374   - }
  422 + if (strcmp(cmd, "env.oob") == 0)
  423 + return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
375 424 #endif
376 425  
377   - /* the following commands operate on the current device */
378   - if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
379   - !nand_info[nand_curr_device].name) {
  426 + /* The following commands operate on the current device, unless
  427 + * overridden by a partition specifier. Note that if somehow the
  428 + * current device is invalid, it will have to be changed to a valid
  429 + * one before these commands can run, even if a partition specifier
  430 + * for another device is to be used.
  431 + */
  432 + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
  433 + !nand_info[dev].name) {
380 434 puts("\nno devices available\n");
381 435 return 1;
382 436 }
383   - nand = &nand_info[nand_curr_device];
  437 + nand = &nand_info[dev];
384 438  
385 439 if (strcmp(cmd, "bad") == 0) {
386   - printf("\nDevice %d bad blocks:\n", nand_curr_device);
  440 + printf("\nDevice %d bad blocks:\n", dev);
387 441 for (off = 0; off < nand->size; off += nand->erasesize)
388 442 if (nand_block_isbad(nand, off))
389   - printf(" %08lx\n", off);
  443 + printf(" %08llx\n", (unsigned long long)off);
390 444 return 0;
391 445 }
392 446  
393 447  
... ... @@ -404,9 +458,11 @@
404 458  
405 459 printf("\nNAND %s: ", scrub ? "scrub" : "erase");
406 460 /* skip first two or three arguments, look for offset and size */
407   - if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
  461 + if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0)
408 462 return 1;
409 463  
  464 + nand = &nand_info[dev];
  465 +
410 466 memset(&opts, 0, sizeof(opts));
411 467 opts.offset = off;
412 468 opts.length = size;
... ... @@ -462,6 +518,7 @@
462 518 }
463 519  
464 520 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
  521 + size_t rwsize;
465 522 int read;
466 523  
467 524 if (argc < 4)
468 525  
469 526  
470 527  
471 528  
... ... @@ -471,23 +528,26 @@
471 528  
472 529 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
473 530 printf("\nNAND %s: ", read ? "read" : "write");
474   - if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
  531 + if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size) != 0)
475 532 return 1;
476 533  
  534 + nand = &nand_info[dev];
  535 + rwsize = size;
  536 +
477 537 s = strchr(cmd, '.');
478 538 if (!s || !strcmp(s, ".jffs2") ||
479 539 !strcmp(s, ".e") || !strcmp(s, ".i")) {
480 540 if (read)
481   - ret = nand_read_skip_bad(nand, off, &size,
  541 + ret = nand_read_skip_bad(nand, off, &rwsize,
482 542 (u_char *)addr);
483 543 else
484   - ret = nand_write_skip_bad(nand, off, &size,
  544 + ret = nand_write_skip_bad(nand, off, &rwsize,
485 545 (u_char *)addr);
486 546 } else if (!strcmp(s, ".oob")) {
487 547 /* out-of-band data */
488 548 mtd_oob_ops_t ops = {
489 549 .oobbuf = (u8 *)addr,
490   - .ooblen = size,
  550 + .ooblen = rwsize,
491 551 .mode = MTD_OOB_RAW
492 552 };
493 553  
... ... @@ -500,7 +560,7 @@
500 560 return 1;
501 561 }
502 562  
503   - printf(" %zu bytes %s: %s\n", size,
  563 + printf(" %zu bytes %s: %s\n", rwsize,
504 564 read ? "read" : "written", ret ? "ERROR" : "OK");
505 565  
506 566 return ret == 0 ? 0 : 1;
... ... @@ -564,7 +624,7 @@
564 624 if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
565 625 return 1;
566 626  
567   - if (!nand_unlock(nand, off, size)) {
  627 + if (!nand_unlock(&nand_info[dev], off, size)) {
568 628 puts("NAND flash successfully unlocked\n");
569 629 } else {
570 630 puts("Error unlocking NAND flash, "