基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现
4. u-boot-1.2.0中nand flash命令的支持及其实现
4.1. u-boot支持nand flash的命令
"nand - legacy NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2[s]] addr off size\n"
"nand write[.jffs2] addr off size - read/write `size' bytes starting at offset `off' to/from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand read.oob addr off size - read out-of-band data\n"
"nand write.oob addr off size - read out-of-band data\n"
4.2. 涉及文件
include/cmd_confdefs.h
include/command.h
common/command.c
include/configs/smdk2410.h
4.3. 具体分析
U-Boot的每一个命令都是通过U_Boot_CMD宏定义的。这个宏在include/command.h头文件中定义,每一个命令定义一个cmd_tbl_t结构体。
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
这样每一个U-Boot命令有一个结构体来描述。结构体包含的成员变量:命令名称、最大参数个数、重复数、命令执行函数、用法、帮助。
从控制台输入的命令是由common/command.c中的程序解释执行的。find_cmd()负责匹配输入的命令,从列表中找出对应的命令结构体。
定义nand命令。在include/cmd_confdefs.h中定义了所有U-Boot命令的标志位。
#define CFG_CMD_NAND 0x0000800000000000ULL /* NAND support */
如果有更多的命令,也要在这里添加定义。
实现nand命令的操作函数。下面是common/cmd_nand.c文件的部分代码。
nt do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
int rcode = 0;
switch (argc) {
case 0:
case 1:
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
case 2:
if (strcmp (argv[1], "info") == 0) {
int i;
putc ('\n');
for (i = 0; i < CFG_MAX_NAND_DEVICE; ++i) {
if (nand_dev_desc[i].ChipID ==
NAND_ChipID_UNKNOWN)
continue; /* list only known devices */
printf ("Device %d: ", i);
nand_print (&nand_dev_desc[i]);
}
return 0;
} else if (strcmp (argv[1], "device") == 0) {
if ((curr_device < 0)
|| (curr_device >= CFG_MAX_NAND_DEVICE)) {
puts ("\nno devices available\n");
return 1;
}
printf ("\nDevice %d: ", curr_device);
nand_print (&nand_dev_desc[curr_device]);
return 0;
} else if (strcmp (argv[1], "bad") == 0) {
if ((curr_device < 0)
|| (curr_device >= CFG_MAX_NAND_DEVICE)) {
puts ("\nno devices available\n");
return 1;
}
printf ("\nDevice %d bad blocks:\n", curr_device);
nand_print_bad (&nand_dev_desc[curr_device]);
return 0;
}
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
case 3:
if (strcmp (argv[1], "device") == 0) {
int dev = (int) simple_strtoul (argv[2], NULL, 10);
printf ("\nDevice %d: ", dev);
if (dev >= CFG_MAX_NAND_DEVICE) {
puts ("unknown device\n");
return 1;
}
nand_print (&nand_dev_desc[dev]);
/*nand_print (dev); */
if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
return 1;
}
curr_device = dev;
puts ("... is now current device\n");
return 0;
} else if (strcmp (argv[1], "erase") == 0
&& strcmp (argv[2], "clean") == 0) {
struct nand_chip *nand = &nand_dev_desc[curr_device];
ulong off = 0;
ulong size = nand->totlen;
int ret;
printf ("\nNAND erase: device %d offset %ld, size %ld ... ", curr_device, off, size);
ret = nand_legacy_erase (nand, off, size, 1);
printf ("%s\n", ret ? "ERROR" : "OK");
return ret;
}
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
default:
/* at least 4 args */
if (strncmp (argv[1], "read", 4) == 0 ||
strncmp (argv[1], "write", 5) == 0) {
ulong addr = simple_strtoul (argv[2], NULL, 16);
ulong off = simple_strtoul (argv[3], NULL, 16);
ulong size = simple_strtoul (argv[4], NULL, 16);
int cmd = (strncmp (argv[1], "read", 4) == 0) ?
NANDRW_READ : NANDRW_WRITE;
int ret, total;
char *cmdtail = strchr (argv[1], '.');
if (cmdtail && !strncmp (cmdtail, ".oob", 2)) {
/* read out-of-band data */
if (cmd & NANDRW_READ) {
ret = nand_read_oob (nand_dev_desc + curr_device,
off, size, (size_t *) & total,
(u_char *) addr);
} else {
ret = nand_write_oob (nand_dev_desc + curr_device,
off, size, (size_t *) & total,
(u_char *) addr);
}
return ret;
} else if (cmdtail && !strncmp (cmdtail, ".jffs2", 2))
cmd |= NANDRW_JFFS2; /* skip bad blocks */
else if (cmdtail && !strncmp (cmdtail, ".jffs2s", 2)) {
cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
if (cmd & NANDRW_READ)
cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
}
#ifdef SXNI855T
/* need ".e" same as ".j" for compatibility with older units */
else if (cmdtail && !strcmp (cmdtail, ".e"))
cmd |= NANDRW_JFFS2; /* skip bad blocks */
#endif
#ifdef CFG_NAND_SKIP_BAD_DOT_I
/* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
/* ".i" for image -> read skips bad block (no 0xff) */
else if (cmdtail && !strcmp (cmdtail, ".i")) {
cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
if (cmd & NANDRW_READ)
cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
}
#endif /* CFG_NAND_SKIP_BAD_DOT_I */
else if (cmdtail) {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
printf ("\nNAND %s: device %d offset %ld, size %ld ...\n",
(cmd & NANDRW_READ) ? "read" : "write",
curr_device, off, size);
ret = nand_legacy_rw (nand_dev_desc + curr_device,
cmd, off, size,
(size_t *) & total,
(u_char *) addr);
printf (" %d bytes %s: %s\n", total,
(cmd & NANDRW_READ) ? "read" : "written",
ret ? "ERROR" : "OK");
return ret;
} else if (strcmp (argv[1], "erase") == 0 &&
(argc == 4 || strcmp ("clean", argv[2]) == 0)) {
int clean = argc == 5;
ulong off =
simple_strtoul (argv[2 + clean], NULL, 16);
ulong size =
simple_strtoul (argv[3 + clean], NULL, 16);
int ret;
printf ("\nNAND erase: device %d offset %ld, size %ld ...\n",
curr_device, off, size);
ret = nand_legacy_erase (nand_dev_desc + curr_device,
off, size, clean);
printf ("%s\n", ret ? "ERROR" : "OK");
return ret;
} else {
printf ("Usage:\n%s\n", cmdtp->usage);
rcode = 1;
}
return rcode;
}
}
U_BOOT_CMD(
nand, 5, 1, do_nand, /* nand 命令和nand函数的映射 */
"nand - legacy NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2[s]] addr off size\n"
"nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand read.oob addr off size - read out-of-band data\n"
"nand write.oob addr off size - read out-of-band data\n"
);
U-Boot的命令都是通过结构体__U_Boot_cmd_##name来描述的。根据U_Boot_CMD在include/command.h中的两行定义可以明白。
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
在common/Makefile中添加编译的目标文件。
打开CONFIG_COMMANDS选项的命令标志位。这个程序文件开头有#if语句需要预处理是否包含这个命令函数。CONFIG_COMMANDS选项在开发板的配置文件中定义。SMDK2410平台在include/configs/smdk2410.h中有如下定义。
/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \ /* 打开nand flash命令 */
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I2C |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
按照上面的操作就可以实现u-boot对nand flash命令的支持