-
yaoff = nandoff/0x800 * 0x840
-
nandoff = ya_off/0x840 * 0x800
-
*cmdtp即cmd_tb_t的位置,执行命令时会一直往下传递(可能传递给下一个命令),万一出错会根据cmdtp打印执行最早的命令的帮助信息。
-
-
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, maxsize;
-
char *cmd, *s;
-
nand_info_t *nand;
-
#ifdef CONFIG_SYS_NAND_QUIET
-
int quiet = CONFIG_SYS_NAND_QUIET;
-
#else
-
int quiet = 0;
-
#endif /* CONFIG_SYS_NAND_QUIET */
-
const char *quiet_str = getenv("quiet");
-
int dev = nand_curr_device;
-
int repeat = flag & CMD_FLAG_REPEAT;
-
-
/* at least two arguments please */
-
if (argc < 2)
-
goto usage;
-
-
if (quiet_str)
-
quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
-
-
cmd = argv[1];
-
-
/* Only "dump" is repeatable. */
-
if (repeat && strcmp(cmd, "dump"))
-
return 0;
-
-
if (strcmp(cmd, "info") == 0) {
-
-
putc('\n');
-
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
-
if (nand_info[i].name)
-
nand_print_and_set_info(i);
-
}
-
return 0;
-
}
-
-
if (strcmp(cmd, "device") == 0) {
-
if (argc < 3) {
-
putc('\n');
-
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
-
puts("no devices available\n");
-
else
-
nand_print_and_set_info(dev);
-
return 0;
-
}
-
-
dev = (int)simple_strtoul(argv[2], NULL, 10);
-
set_dev(dev);
-
-
return 0;
-
}
-
-
#ifdef CONFIG_ENV_OFFSET_OOB
-
/* this command operates only on the first nand device */
-
if (strcmp(cmd, "env.oob") == 0)
-
return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
-
#endif /* CONFIG_ENV_OFFSET_OOB */
-
-
/* The following commands operate on the current device, unless
-
* overridden by a partition specifier. Note that if somehow the
-
* current device is invalid, it will have to be changed to a valid
-
* one before these commands can run, even if a partition specifier
-
* for another device is to be used.
-
*/
-
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
-
!nand_info[dev].name) {
-
puts("\nno devices available\n");
-
return 1;
-
}
-
nand = &nand_info[dev];
-
-
if (strcmp(cmd, "bad") == 0) {
-
printf("\nDevice %d bad blocks:\n", dev);
-
for (off = 0; off < nand->size; off += nand->erasesize)
-
if (nand_block_isbad(nand, off))
-
printf(" %08llx\n", (unsigned long long)off);
-
return 0;
-
}
-
-
/*
-
* Syntax is:
-
* 0 1 2 3 4
-
* nand erase [clean] [off size]
-
*/
-
if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
-
nand_erase_options_t opts;
-
/* "clean" at index 2 means request to write cleanmarker */
-
int clean = argc > 2 && !strcmp("clean", argv[2]);
-
int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
-
int o = (clean || scrub_yes) ? 3 : 2;
-
int scrub = !strncmp(cmd, "scrub", 5);
-
int spread = 0;
-
int args = 2;
-
const char *scrub_warn =
-
"Warning: "
-
"scrub option will erase all factory set bad blocks!\n"
-
" "
-
"There is no reliable way to recover them.\n"
-
" "
-
"Use this command only for testing purposes if you\n"
-
" "
-
"are sure of what you are doing!\n"
-
"\nReally scrub this NAND flash? <y/N>\n";
-
-
if (cmd[5] != 0) {
-
if (!strcmp(&cmd[5], ".spread")) {
-
spread = 1;
-
} else if (!strcmp(&cmd[5], ".part")) {
-
args = 1;
-
} else if (!strcmp(&cmd[5], ".chip")) {
-
args = 0;
-
} else {
-
goto usage;
-
}
-
}
-
-
/*
-
* Don't allow missing arguments to cause full chip/partition
-
* erases -- easy to do accidentally, e.g. with a misspelled
-
* variable name.
-
*/
-
if (argc != o + args)
-
goto usage;
-
-
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,
-
&maxsize) != 0)
-
return 1;
-
-
nand = &nand_info[dev];
-
-
-
//擦除初始化
-
memset(&opts, 0, sizeof(opts));
-
opts.offset = off;
-
opts.length = size;
-
opts.jffs2 = clean;//jffs2专用
-
opts.quiet = quiet;
-
opts.spread = spread;// 遇到坏块是否要忽略,总擦除长度 = length + 坏块
-
-
if (scrub) {
-
if (!scrub_yes)
-
puts(scrub_warn);
-
-
if (scrub_yes)
-
opts.scrub = 1;
-
else if (getc() == 'y') {
-
puts("y");
-
if (getc() == '\r')
-
opts.scrub = 1;
-
else {
-
puts("scrub aborted\n");
-
return 1;
-
}
-
} else {
-
puts("scrub aborted\n");
-
return 1;
-
}
-
}
-
ret = nand_erase_opts(nand, &opts);//开始擦除
-
printf("%s\n", ret ? "ERROR" : "OK");
-
-
return ret == 0 ? 0 : 1;
-
}
-
-
if (strncmp(cmd, "dump", 4) == 0) {
-
if (argc < 3)
-
goto usage;
-
-
off = (int)simple_strtoul(argv[2], NULL, 16);
-
ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat);
-
-
return ret == 0 ? 1 : 0;
-
}
-
-
//读写命令从这里开始,cmd = argv[1]
-
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
-
//比较前4个是否等于"read"或"write"
-
size_t rwsize;
-
ulong pagecount = 1;
-
int read;
-
int raw = 0;
-
-
if (argc < 4)//读写命令的参数至少是4个。
-
goto usage;
-
-
addr = (ulong)simple_strtoul(argv[2], NULL, 16);//十六进制字符串转地址(十进制),addr是内存地址
-
-
read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
-
printf("\nNAND %s: ", read ? "read" : "write");
-
-
nand = &nand_info[dev];//获得当前nand设备对象,dev = nand_curr_device
-
s = strchr(cmd, '.');//移动指针到 '.'
-
-
if (s && !strcmp(s, ".raw")) { //如果搜raw格式的读写
-
raw = 1;
-
-
if (arg_off(argv[3], &dev, &off, &size, &maxsize))//调用arg_off从参数获取off size maxsize等参数
-
return 1;
-
-
if (argc > 4 && !str2long(argv[4], &pagecount)) {
-
printf("'%s' is not a number\n", argv[4]);
-
return 1;
-
}
-
-
if (pagecount * nand->writesize > size) {
-
puts("Size exceeds partition or device limit\n");
-
return -1;
-
}
-
-
rwsize = pagecount * (nand->writesize + nand->oobsize);
-
} else {// 如果找不到 '.',则说明命令格式为 nand read add off [size]或者 nand write addr off [size]
-
-
//从argv[3]获得十进制off,size maxsize。如果不是分区名,默认size = maxsize(off后面的所有空间)
-
//如果argc=5,则有size参数,argc-3 = 2,argv + 3 = offset
-
if (arg_off_size(argc - 3, argv + 3, &dev,
-
&off, &size, &maxsize) != 0)
-
return 1;
-
-
if (argc < 5)////如果参数没有指定size,说明offset是分区名
-
//我们需要调整size和maxsize忽略坏块,以免读写超出分区边界
-
adjust_size_for_badblocks(&size, off, dev);
-
rwsize = size;//得到读写长度
-
}
-
-
//如果read或write不带.参数、或者.jffs2 .e .i
-
if (!s || !strcmp(s, ".jffs2") ||
-
!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, flag);
-
#ifdef CONFIG_CMD_NAND_TRIMFFS
-
} else if (!strcmp(s, ".trimffs")) {
-
if (read) {
-
printf("Unknown nand command suffix '%s'\n", s);
-
return 1;
-
}
-
ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
-
maxsize, (u_char *)addr,
-
WITH_DROP_FFS);
-
#endif
-
#ifdef CONFIG_CMD_NAND_YAFFS
-
} else if (!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs2")) {
-
if (read) {
-
printf("Unknown nand command suffix '%s'.\n", s);
-
return 1;
-
}
-
ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
-
maxsize, (u_char *)addr,
-
flag | WITH_YAFFS_OOB);
-
#endif /* CONFIG_CMD_NAND_YAFFS */
-
} else if (!strcmp(s, ".oob")) {
-
/* out-of-band data */
-
mtd_oob_ops_t ops = {
-
.oobbuf = (u8 *)addr,
-
.ooblen = rwsize,
-
.mode = MTD_OPS_RAW
-
};
-
-
if (read)
-
ret = mtd_read_oob(nand, off, &ops);
-
else
-
ret = mtd_write_oob(nand, off, &ops);
-
} else if (raw) {
-
ret = raw_access(nand, addr, off, pagecount, read);
-
} else {
-
printf("Unknown nand command suffix '%s'.\n", s);
-
return 1;
-
}
-
-
printf(" %zu bytes %s: %s\n", rwsize,
-
read ? "read" : "written", ret ? "ERROR" : "OK");
-
-
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 /* CONFIG_CMD_NAND_TORTURE */
-
-
if (strcmp(cmd, "markbad") == 0) {
-
argc -= 2;
-
argv += 2;
-
-
if (argc <= 0)
-
goto usage;
-
-
while (argc > 0) {
-
addr = simple_strtoul(*argv, NULL, 16);
-
-
if (mtd_block_markbad(nand, addr)) {
-
printf("block 0x%08lx NOT marked "
-
"as bad! ERROR %d\n",
-
addr, ret);
-
ret = 1;
-
} else {
-
printf("block 0x%08lx successfully "
-
"marked as bad\n",
-
addr);
-
}
-
--argc;
-
++argv;
-
}
-
return ret;
-
}
-
-
if (strcmp(cmd, "biterr") == 0) {
-
/* todo */
-
return 1;
-
}
-
-
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
-
if (strcmp(cmd, "lock") == 0) {
-
int tight = 0;
-
int status = 0;
-
if (argc == 3) {
-
if (!strcmp("tight", argv[2]))
-
tight = 1;
-
if (!strcmp("status", argv[2]))
-
status = 1;
-
}
-
if (status) {
-
do_nand_status(nand);
-
} else {
-
if (!nand_lock(nand, tight)) {
-
puts("NAND flash successfully locked\n");
-
} else {
-
puts("Error locking NAND flash\n");
-
return 1;
-
}
-
}
-
return 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, allexcept)) {
-
puts("NAND flash successfully unlocked\n");
-
} else {
-
puts("Error unlocking NAND flash, "
-
"write and erase will probably fail\n");
-
return 1;
-
}
-
return 0;
-
}
-
#endif /* CONFIG_CMD_NAND_LOCK_UNLOCK */
-
-
usage:
-
return CMD_RET_USAGE;
-
}
-
-
//字符串转为偏移地址,如果是分区名同时得到size,最大可写长度
-
static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
-
loff_t *maxsize)
-
{
-
if (!str2off(arg, off))//字符串转换为偏移地址,参数可以是分区名,失败则认为参数是分区名,调用get_part得到off size 和maxsize,return
-
return get_part(arg, idx, off, size, maxsize);
-
-
if (*off >= nand_info[*idx].size) { //如果偏移地址超过nand容量则报错
-
puts("Offset exceeds device limit\n");
-
return -1;
-
}
-
-
*maxsize = nand_info[*idx].size - *off;//如果off不是分区名,得到最大可写长度 = size -off
-
*size = *maxsize;//写入尺寸等于最大可写长度,后面会修改
-
return 0;
-
}
-
-
//封装arg_off函数
-
int arg_off_size(int argc, char *const argv[], int *idx,
-
loff_t *off, loff_t *size, loff_t *maxsize)
-
{
-
int ret;
-
-
if (argc == 0) {
-
*off = 0;
-
*size = nand_info[*idx].size;//如果没有参数,则写长度为whole chip,size和maxsize默认最大值
-
*maxsize = *size;
-
goto print;
-
}
-
-
ret = arg_off(argv[0], idx, off, size, maxsize);
-
//字符串转为偏移地址,如果是分区名则得到写长度size和最大可写长度,立即return,否则size和maxsize默认最大值
-
if (ret)
-
return ret;
-
-
if (argc == 1)
-
goto print;
-
-
if (!str2off(argv[1], size)) {//从argv[1]转为size
-
printf("'%s' is not a number\n", argv[1]);
-
return -1;
-
}
-
-
if (*size > *maxsize) {
-
puts("Size exceeds partition or device limit\n");
-
return -1;
-
}
-
-
print:
-
printf("device %d ", *idx);
-
if (*size == nand_info[*idx].size)
-
puts("whole chip\n");
-
else
-
printf("offset 0x%llx, size 0x%llx\n",
-
(unsigned long long)*off, (unsigned long long)*size);
-
return 0;
-
}
-
-
-
//如果参数没有指定size,我们需要忽略坏块,调整size和offset(减去坏块长度)
-
void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
-
{
-
/* We grab the nand info object here fresh because this is usually
-
* called after arg_off_size() which can change the value of dev.
-
*/
-
nand_info_t *nand = &nand_info[dev];//获取nand对象
-
loff_t maxoffset = offset + *size;//最大偏移,如果指定了分区,则maxoffset为分区边界;如果没有指定分区,则maxoffset为nand边界
-
int badblocks = 0;
-
-
/* count badblocks in NAND from offset to offset + size */
-
for (; offset < maxoffset; offset += nand->erasesize) {
-
if (nand_block_isbad(nand, offset))
-
badblocks++;//统计坏块
-
}
-
/* adjust size if any bad blocks found */
-
if (badblocks) {
-
*size -= badblocks * nand->erasesize;
-
printf("size adjusted to 0x%llx (%d bad blocks)\n",
-
(unsigned long long)*size, badblocks);//有x个坏块,因此size会减少(x * erasesize)
-
}
-
}
阅读(2382) | 评论(0) | 转发(0) |