X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=common%2Fcmd_nand.c;h=e9d3d3c1bf6238d20ad3abc310cbc306fab473dd;hb=c4df2f41005063cf1d1dcddeed4bd7f12a5dff77;hp=4367f5a0f2ccf28cc6e52e024502984d406aa38c;hpb=d193c1b6eb05041c94ad9aacd8c94189d1dbc5f8;p=platform%2Fkernel%2Fu-boot.git diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 4367f5a..e9d3d3c 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -137,7 +137,8 @@ static inline int str2long(const char *p, ulong *num) return *p != '\0' && *endptr == '\0'; } -static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) +static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size, + loff_t *maxsize) { #ifdef CONFIG_CMD_MTDPARTS struct mtd_device *dev; @@ -160,6 +161,7 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) *off = part->offset; *size = part->size; + *maxsize = part->size; *idx = dev->id->num; ret = set_dev(*idx); @@ -173,10 +175,11 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) #endif } -static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) +static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, + loff_t *maxsize) { if (!str2off(arg, off)) - return get_part(arg, idx, off, maxsize); + return get_part(arg, idx, off, size, maxsize); if (*off >= nand_info[*idx].size) { puts("Offset exceeds device limit\n"); @@ -184,36 +187,35 @@ static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) } *maxsize = nand_info[*idx].size - *off; + *size = *maxsize; return 0; } static int arg_off_size(int argc, char *const argv[], int *idx, - loff_t *off, loff_t *size) + loff_t *off, loff_t *size, loff_t *maxsize) { int ret; - loff_t maxsize = 0; if (argc == 0) { *off = 0; *size = nand_info[*idx].size; + *maxsize = *size; goto print; } - ret = arg_off(argv[0], idx, off, &maxsize); + ret = arg_off(argv[0], idx, off, size, maxsize); if (ret) return ret; - if (argc == 1) { - *size = maxsize; + if (argc == 1) goto print; - } if (!str2off(argv[1], size)) { printf("'%s' is not a number\n", argv[1]); return -1; } - if (*size > maxsize) { + if (*size > *maxsize) { puts("Size exceeds partition or device limit\n"); return -1; } @@ -231,12 +233,18 @@ print: #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK static void print_status(ulong start, ulong end, ulong erasesize, int status) { + /* + * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is + * not the same as others. Instead of bit 1 being lock, it is + * #lock_tight. To make the driver support either format, ignore bit 1 + * and use only bit 0 and bit 2. + */ printf("%08lx - %08lx: %08lx blocks %s%s%s\n", start, end - 1, (end - start) / erasesize, ((status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), - ((status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), + (!(status & NAND_LOCK_STATUS_UNLOCK) ? "LOCK " : ""), ((status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); } @@ -301,7 +309,8 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[]) if (argc < 3) goto usage; - if (arg_off(argv[2], &idx, &addr, &maxsize)) { + /* We don't care about size, or maxsize. */ + if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) { puts("Offset or partition name expected\n"); return 1; } @@ -367,8 +376,6 @@ static void nand_print_and_set_info(int idx) { nand_info_t *nand = &nand_info[idx]; struct nand_chip *chip = nand->priv; - const int bufsz = 32; - char buf[bufsz]; printf("Device %d: ", idx); if (chip->numchips > 1) @@ -380,14 +387,9 @@ static void nand_print_and_set_info(int idx) printf(" Erase size %8d b\n", nand->erasesize); /* Set geometry info */ - sprintf(buf, "%x", nand->writesize); - setenv("nand_writesize", buf); - - sprintf(buf, "%x", nand->oobsize); - setenv("nand_oobsize", buf); - - sprintf(buf, "%x", nand->erasesize); - setenv("nand_erasesize", buf); + setenv_hex("nand_writesize", nand->writesize); + setenv_hex("nand_oobsize", nand->oobsize); + setenv_hex("nand_erasesize", nand->erasesize); } static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, @@ -423,11 +425,11 @@ static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, return ret; } -int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, ret = 0; ulong addr; - loff_t off, size; + loff_t off, size, maxsize; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET @@ -552,7 +554,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) printf("\nNAND %s: ", cmd); /* skip first two or three arguments, look for offset and size */ - if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0) + if (arg_off_size(argc - o, argv + o, &dev, &off, &size, + &maxsize) != 0) return 1; nand = &nand_info[dev]; @@ -603,7 +606,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) size_t rwsize; ulong pagecount = 1; int read; - int raw; + int raw = 0; if (argc < 4) goto usage; @@ -620,7 +623,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) if (s && !strcmp(s, ".raw")) { raw = 1; - if (arg_off(argv[3], &dev, &off, &size)) + if (arg_off(argv[3], &dev, &off, &size, &maxsize)) return 1; if (argc > 4 && !str2long(argv[4], &pagecount)) { @@ -636,7 +639,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) rwsize = pagecount * (nand->writesize + nand->oobsize); } else { if (arg_off_size(argc - 3, argv + 3, &dev, - &off, &size) != 0) + &off, &size, &maxsize) != 0) return 1; rwsize = size; @@ -646,9 +649,11 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &rwsize, + NULL, maxsize, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &rwsize, + NULL, maxsize, (u_char *)addr, 0); #ifdef CONFIG_CMD_NAND_TRIMFFS } else if (!strcmp(s, ".trimffs")) { @@ -656,8 +661,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) printf("Unknown nand command suffix '%s'\n", s); return 1; } - ret = nand_write_skip_bad(nand, off, &rwsize, - (u_char *)addr, + ret = nand_write_skip_bad(nand, off, &rwsize, NULL, + maxsize, (u_char *)addr, WITH_DROP_FFS); #endif #ifdef CONFIG_CMD_NAND_YAFFS @@ -666,9 +671,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) printf("Unknown nand command suffix '%s'.\n", s); return 1; } - ret = nand_write_skip_bad(nand, off, &rwsize, - (u_char *)addr, - WITH_INLINE_OOB); + ret = nand_write_skip_bad(nand, off, &rwsize, NULL, + maxsize, (u_char *)addr, + WITH_YAFFS_OOB); #endif } else if (!strcmp(s, ".oob")) { /* out-of-band data */ @@ -695,6 +700,25 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return ret == 0 ? 0 : 1; } +#ifdef CONFIG_CMD_NAND_TORTURE + if (strcmp(cmd, "torture") == 0) { + if (argc < 3) + goto usage; + + if (!str2off(argv[2], &off)) { + puts("Offset is not a valid number\n"); + return 1; + } + + printf("\nNAND torture: device %d offset 0x%llx size 0x%x\n", + dev, off, nand->erasesize); + ret = nand_torture(nand, off); + printf(" %s\n", ret ? "Failed" : "Passed"); + + return ret == 0 ? 0 : 1; + } +#endif + if (strcmp(cmd, "markbad") == 0) { argc -= 2; argv += 2; @@ -749,11 +773,19 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return 0; } - if (strcmp(cmd, "unlock") == 0) { - if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0) + if (strncmp(cmd, "unlock", 5) == 0) { + int allexcept = 0; + + s = strchr(cmd, '.'); + + if (s && !strcmp(s, ".allexcept")) + allexcept = 1; + + if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size, + &maxsize) < 0) return 1; - if (!nand_unlock(&nand_info[dev], off, size)) { + if (!nand_unlock(&nand_info[dev], off, size, allexcept)) { puts("NAND flash successfully unlocked\n"); } else { puts("Error unlocking NAND flash, " @@ -768,9 +800,8 @@ usage: return CMD_RET_USAGE; } -U_BOOT_CMD( - nand, CONFIG_SYS_MAXARGS, 1, do_nand, - "NAND sub-system", +#ifdef CONFIG_SYS_LONGHELP +static char nand_help_text[] = "info - show available NAND devices\n" "nand device [dev] - show or set current device\n" "nand read - addr off|partition size\n" @@ -799,6 +830,9 @@ U_BOOT_CMD( "nand erase.chip [clean] - erase entire chip'\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" +#ifdef CONFIG_CMD_NAND_TORTURE + "nand torture off - torture block at offset\n" +#endif "nand scrub [-y] off size | scrub.part partition | scrub.chip\n" " really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n" @@ -807,7 +841,7 @@ U_BOOT_CMD( "\n" "nand lock [tight] [status]\n" " bring nand to lock state or display locked pages\n" - "nand unlock [offset] [size] - unlock section" + "nand unlock[.allexcept] [offset] [size] - unlock section" #endif #ifdef CONFIG_ENV_OFFSET_OOB "\n" @@ -816,6 +850,12 @@ U_BOOT_CMD( "nand env.oob set off|partition - set enviromnent offset\n" "nand env.oob get - get environment offset" #endif + ""; +#endif + +U_BOOT_CMD( + nand, CONFIG_SYS_MAXARGS, 1, do_nand, + "NAND sub-system", nand_help_text ); static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, @@ -840,7 +880,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); cnt = nand->writesize; - r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); + r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, + (u_char *)addr); if (r) { puts("** Read error\n"); bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ); @@ -872,7 +913,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, } bootstage_mark(BOOTSTAGE_ID_NAND_TYPE); - r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); + r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, + (u_char *)addr); if (r) { puts("** Read error\n"); bootstage_error(BOOTSTAGE_ID_NAND_READ); @@ -900,7 +942,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, return bootm_maybe_autostart(cmdtp, cmd); } -int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +static int do_nandboot(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { char *boot_device = NULL; int idx;