本文主要探讨210的uboot命令体系,黄金变量,iNand/SD卡驱动相关知识。
命令体系
uboot命令体系
位置:uboot/common/
参数:uboot命令支持传递参数(argc,argv)
函数:xxx命令的实现算数为do_xxx
/*
* Use puts() instead of printf() to avoid printf buffer overflow
* for long help messages
*/
int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
int i;
int rcode = 0;
if (argc == 1) { /*show list of commands */
int cmd_items = &__u_boot_cmd_end -
&__u_boot_cmd_start; /* pointer arith! */
cmd_tbl_t *cmd_array[cmd_items];
int i, j, swaps;
/* Make array of commands from .uboot_cmd section */
cmdtp = &__u_boot_cmd_start;
for (i = 0; i < cmd_items; i++) {
cmd_array[i] = cmdtp++;
}
/* Sort command list (trivial bubble sort) */
for (i = cmd_items - 1; i > 0; --i) {
swaps = 0;
for (j = 0; j < i; ++j) {
if (strcmp (cmd_array[j]->name,
cmd_array[j + 1]->name) > 0) {
cmd_tbl_t *tmp;
tmp = cmd_array[j];
cmd_array[j] = cmd_array[j + 1];
cmd_array[j + 1] = tmp;
++swaps;
}
}
if (!swaps)
break;
}
/* print short help (usage) */
for (i = 0; i < cmd_items; i++) {
const char *usage = cmd_array[i]->usage;
/* allow user abort */
if (ctrlc ())
return 1;
if (usage == NULL)
continue;
puts (usage);
}
return 0;
}
/*
* command help (long version)
*/
for (i = 1; i < argc; ++i) {
if ((cmdtp = find_cmd (argv[i])) != NULL) {
#ifdef CFG_LONGHELP
/* found - print (long) help info */
puts (cmdtp->name);
putc (' ');
if (cmdtp->help) {
puts (cmdtp->help);
} else {
puts ("- No help available.\n");
rcode = 1;
}
putc ('\n');
#else /* no long help available */
if (cmdtp->usage)
puts (cmdtp->usage);
#endif /* CFG_LONGHELP */
} else {
printf ("Unknown command '%s' - try 'help'"
" without arguments for list of all"
" known commands\n\n", argv[i]
);
rcode = 1;
}
}
return rcode;
}
命令解析和执行
uboot二阶段初始化完成进入main_loop循环,main_loop执行一次为一条命令的获取,解析,执行(run_command)的过程
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
run_command
控制台命令获取
命令解析(parse_line)为命令和参数
执行命令:用函数指针方式调用命令函数
/****************************************************************************
* returns:
* 1 - command executed, repeatable
* 0 - command executed but not repeatable, interrupted commands are
* always considered not repeatable
* -1 - not executed (unrecognized, bootd recursion or too many args)
* (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
* considered unrecognized)
*
* WARNING:
*
* We must create a temporary copy of the command since the command we get
* may be the result from getenv(), which returns a pointer directly to
* the environment data, which may change magicly when the command we run
* creates or modifies environment variables (like "bootp" does).
*/
int run_command (const char *cmd, int flag)
{
cmd_tbl_t *cmdtp;
char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
char *token; /* start of token in cmdbuf */
char *sep; /* end of token (separator) in cmdbuf */
char finaltoken[CFG_CBSIZE];
char *str = cmdbuf;
char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
int argc, inquotes;
int repeatable = 1;
int rc = 0;
#ifdef DEBUG_PARSER
printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
puts ("\"\n");
#endif
clear_ctrlc(); /* forget any previous Control C */
if (!cmd || !*cmd) {
return -1; /* empty command */
}
if (strlen(cmd) >= CFG_CBSIZE) {
puts ("## Command too long!\n");
return -1;
}
strcpy (cmdbuf, cmd);
/* Process separators and check for invalid
* repeatable commands
*/
#ifdef DEBUG_PARSER
printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endif
while (*str) {
/*
* Find separator, or string end
* Allow simple escape of ';' by writing "\;"
*/
for (inquotes = 0, sep = str; *sep; sep++) {
if ((*sep=='\'') &&
(*(sep-1) != '\\'))
inquotes=!inquotes;
if (!inquotes &&
(*sep == ';') && /* separator */
( sep != str) && /* past string start */
(*(sep-1) != '\\')) /* and NOT escaped */
break;
}
/*
* Limit the token to data between separators
*/
token = str;
if (*sep) {
str = sep + 1; /* start of command for next pass */
*sep = '\0';
}
else
str = sep; /* no more commands for next pass */
#ifdef DEBUG_PARSER
printf ("token: \"%s\"\n", token);
#endif
/* find macros in this token and replace them */
process_macros (token, finaltoken);
/* Extract arguments */
if ((argc = parse_line (finaltoken, argv)) == 0) {
rc = -1; /* no command at all */
continue;
}
/* Look up command in command table */
if ((cmdtp = find_cmd(argv[0])) == NULL) {
printf ("Unknown command '%s' - try 'help'\n", argv[0]);
rc = -1; /* give up after bad command */
continue;
}
/* found - check max args */
if (argc > cmdtp->maxargs) {
printf ("Usage:\n%s\n", cmdtp->usage);
rc = -1;
continue;
}
#if defined(CONFIG_CMD_BOOTD)
/* avoid "bootd" recursion */
if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSER
printf ("[%s]\n", finaltoken);
#endif
if (flag & CMD_FLAG_BOOTD) {
puts ("'bootd' recursion detected\n");
rc = -1;
continue;
} else {
flag |= CMD_FLAG_BOOTD;
}
}
#endif
/* OK - call function to do the command */
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
rc = -1;
}
repeatable &= cmdtp->repeatable;
/* Did the user stop this? */
if (had_ctrlc ())
return -1; /* if stopped then not repeatable */
}
return rc ? rc : repeatable;
}
/****************************************************************************/
#if defined(CONFIG_CMD_RUN)
int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
int i;
if (argc < 2) {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
for (i=1; i<argc; ++i) {
char *arg;
if ((arg = getenv (argv[i])) == NULL) {
printf ("## Error: \"%s\" not defined\n", argv[i]);
return 1;
}
#ifndef CFG_HUSH_PARSER
if (run_command (arg, flag) == -1)
return 1;
#else
if (parse_string_outer(arg,
FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
return 1;
#endif
}
return 0;
}
uboot管理命令集
uboot每个命令对应cmd_tbl_t结构体的一个实例,输入命令结构体实例中查找对应的结构体,找到后调用命令函数执行命令
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
typedef struct cmd_tbl_s cmd_tbl_t;
name:命令名称
maxargs:命令最多接收参数
repeatable:命令是否可重复执行(回车重复上条命令)
cmd:命令对应函数,使用函数指针调用命令
usage:命令短介绍
help:命令长介绍
complete:命令自动补(函数指针)
uboot命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性内容链接在一起排列(类似命令结构体数组)
uboot重定位时将该段整体加载到DDR中,段起始和结束地址(链接地址在u-boot.lds)对应命令集开始和结束地址
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
U_BOOT_CMD宏(uboot/common/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}
U_BOOT_CMD(
version, 1, 1, do_version,
"version - print monitor version\n",
NULL
);
宏被替换为:
cmd_tbl_t __u_boot_cmd_version __attribute__ ((unused,section (".u_boot_cmd"))) = {#name, maxargs, rep, cmd, usage, help}
find_cmd
查找命令
/***************************************************************************
* find command table entry for a command
*/
cmd_tbl_t *find_cmd (const char *cmd)
{
cmd_tbl_t *cmdtp;
cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start; /*Init value */
const char *p;
int len;
int n_found = 0;
/*
* Some commands allow length modifiers (like "cp.b");
* compare command name only until first dot.
*/
len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
for (cmdtp = &__u_boot_cmd_start;
cmdtp != &__u_boot_cmd_end;
cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) {
if (len == strlen (cmdtp->name))
return cmdtp; /* full match */
cmdtp_temp = cmdtp; /* abbreviated command ? */
n_found++;
}
}
if (n_found == 1) { /* exactly one match */
return cmdtp_temp;
}
return NULL; /* not found or ambiguous command */
}
find_cmd函数是在uboot命令集中查找命令并返回命令结构体指针,未找到返回NULL
环境变量
uboot环境变量(uboot/common/env_common.c)
优先级:环境变量为空则使用代码中环境变量(代码中定义了环境变量的值),不为空则使用环境变量
machid(机器码定义在x210_sd.h)为2456,可在定义处修改重编译或修改环境变量(set)
SD卡中有变量分区用于存储环境变量,uboot运行时将环境变量读到DDR中,save时将环境变量保存到SD卡
default_environment初始化环境变量(默认),二阶段SD卡的env分区crc校验通过,env_relocate读取SD卡环境变量覆盖default_environment,后面使用的都为SD卡环境变量
默认环境变量存储在default_environment字符数组,大小为CFG_ENV_SIZE(16kb)相邻环境变量用'\0'分隔
void env_crc_update (void)
{
env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
}
void env_relocate (void)
{
DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
gd->reloc_off);
#ifdef CONFIG_AMIGAONEG3SE
enable_nvram();
#endif
#ifdef ENV_IS_EMBEDDED
/*
* The environment buffer is embedded with the text segment,
* just relocate the environment pointer
*/
env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
/*
* We must allocate a buffer for the environment
*/
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif
if (gd->env_valid == 0) {
#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */
puts ("Using default environment\n\n");
#else
puts ("*** Warning - bad CRC, using default environment\n\n");
show_boot_progress (-60);
#endif
set_default_env();
}
else {
env_relocate_spec ();
}
gd->env_addr = (ulong)&(env_ptr->data);
#ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}
/************************************************************************
* Default settings to be used when no valid environment is found
*/
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)
#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430) || defined(CONFIG_S5P6440) || defined(CONFIG_S5PC100) || defined(CONFIG_S5PC110) || defined(CONFIG_S5P6442)
uchar default_environment[CFG_ENV_SIZE] = {
#else
uchar default_environment[] = {
#endif
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif
#if 0 /* for fast booting */
"verify=" MK_STR(no) "\0"
#endif
#ifdef CONFIG_MTDPARTITION
"mtdpart=" CONFIG_MTDPARTITION "\0"
#endif
#ifdef CONFIG_RAMBOOTCOMMAND
"ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
#endif
#ifdef CONFIG_NFSBOOTCOMMAND
"nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
"bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
"baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
#endif
#ifdef CONFIG_LOADS_ECHO
"loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
#endif
#ifdef CONFIG_ETHADDR
"ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
#endif
#ifdef CONFIG_ETH1ADDR
"eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
#endif
#ifdef CONFIG_ETH2ADDR
"eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
#endif
#ifdef CONFIG_ETH3ADDR
"eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"
#endif
#ifdef CONFIG_IPADDR
"ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
#endif
#ifdef CONFIG_SERVERIP
"serverip=" MK_STR(CONFIG_SERVERIP) "\0"
#endif
#ifdef CFG_AUTOLOAD
"autoload=" CFG_AUTOLOAD "\0"
#endif
#ifdef CONFIG_PREBOOT
"preboot=" CONFIG_PREBOOT "\0"
#endif
#ifdef CONFIG_ROOTPATH
"rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
#endif
#ifdef CONFIG_GATEWAYIP
"gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
#endif
#ifdef CONFIG_NETMASK
"netmask=" MK_STR(CONFIG_NETMASK) "\0"
#endif
#ifdef CONFIG_HOSTNAME
"hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
#endif
#ifdef CONFIG_BOOTFILE
"bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
#endif
#ifdef CONFIG_LOADADDR
"loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
#endif
#ifdef CONFIG_CLOCKS_IN_MHZ
"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
"pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
#endif
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
};
环境变量命令(cmd_nvedit.c)
printenv
/************************************************************************
* Command interface: print one or all environment variables
*/
int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int i, j, k, nxt;
int rcode = 0;
if (argc == 1) { /* Print all env variables */
for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)
;
for (k=i; k<nxt; ++k)
putc(env_get_char(k));
putc ('\n');
if (ctrlc()) {
puts ("\n ** Abort\n");
return 1;
}
}
printf("\nEnvironment size: %d/%ld bytes\n",
i, (ulong)ENV_SIZE);
return 0;
}
for (i=1; i<argc; ++i) { /* print single env variables */
char *name = argv[i];
k = -1;
for (j=0; env_get_char(j) != '\0'; j=nxt+1) {
for (nxt=j; env_get_char(nxt) != '\0'; ++nxt)
;
k = envmatch((uchar *)name, j);
if (k < 0) {
continue;
}
puts (name);
putc ('=');
while (k < nxt)
putc(env_get_char(k++));
putc ('\n');
break;
}
if (k < 0) {
printf ("## Error: \"%s\" not defined\n", name);
rcode ++;
}
}
return rcode;
}
argc=1打印所有环境变量出来,argc不为1,打印参数环境变量
setenv
遍历DDR中环境变量,存在则修改,不存在则新建,环境变量为baudrate、ipaddr等全局变量在修改时,同时也需修改gd
int _do_setenv (int flag, int argc, char *argv[])
{
int i, len, oldval;
int console = -1;
uchar *env, *nxt = NULL;
char *name;
bd_t *bd = gd->bd;
uchar *env_data = env_get_addr(0);
if (!env_data) /* need copy in RAM */
return 1;
name = argv[1];
if (strchr(name, '=')) {
printf ("## Error: illegal character '=' in variable name \"%s\"\n", name);
return 1;
}
/*
* search if variable with this name already exists
*/
oldval = -1;
for (env=env_data; *env; env=nxt+1) {
for (nxt=env; *nxt; ++nxt)
;
if ((oldval = envmatch((uchar *)name, env-env_data)) >= 0)
break;
}
/*
* Delete any existing definition
*/
if (oldval >= 0) {
#ifndef CONFIG_ENV_OVERWRITE
/*
* Ethernet Address and serial# can be set only once,
* ver is readonly.
*/
if (
#ifdef CONFIG_HAS_UID
/* Allow serial# forced overwrite with 0xdeaf4add flag */
((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) ||
#else
(strcmp (name, "serial#") == 0) ||
#endif
((strcmp (name, "ethaddr") == 0)
#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
&& (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
) ) {
printf ("Can't overwrite \"%s\"\n", name);
return 1;
}
#endif
/* Check for console redirection */
if (strcmp(name,"stdin") == 0) {
console = stdin;
} else if (strcmp(name,"stdout") == 0) {
console = stdout;
} else if (strcmp(name,"stderr") == 0) {
console = stderr;
}
if (console != -1) {
if (argc < 3) { /* Cannot delete it! */
printf("Can't delete \"%s\"\n", name);
return 1;
}
/* Try assigning specified device */
if (console_assign (console, argv[2]) < 0)
return 1;
#ifdef CONFIG_SERIAL_MULTI
if (serial_assign (argv[2]) < 0)
return 1;
#endif
}
/*
* Switch to new baudrate if new baudrate is supported
*/
if (strcmp(argv[1],"baudrate") == 0) {
int baudrate = simple_strtoul(argv[2], NULL, 10);
int i;
for (i=0; i<N_BAUDRATES; ++i) {
if (baudrate == baudrate_table[i])
break;
}
if (i == N_BAUDRATES) {
printf ("## Baudrate %d bps not supported\n",
baudrate);
return 1;
}
printf ("## Switch baudrate to %d bps and press ENTER ...\n",
baudrate);
udelay(50000);
gd->baudrate = baudrate;
#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
gd->bd->bi_baudrate = baudrate;
#endif
serial_setbrg ();
udelay(50000);
for (;;) {
if (getc() == '\r')
break;
}
}
if (*++nxt == '\0') {
if (env > env_data) {
env--;
} else {
*env = '\0';
}
} else {
for (;;) {
*env = *nxt++;
if ((*env == '\0') && (*nxt == '\0'))
break;
++env;
}
}
*++env = '\0';
}
#ifdef CONFIG_NET_MULTI
if (strncmp(name, "eth", 3) == 0) {
char *end;
int num = simple_strtoul(name+3, &end, 10);
if (strcmp(end, "addr") == 0) {
eth_set_enetaddr(num, argv[2]);
}
}
#endif
/* Delete only ? */
if ((argc < 3) || argv[2] == NULL) {
env_crc_update ();
return 0;
}
/*
* Append new definition at the end
*/
for (env=env_data; *env || *(env+1); ++env)
;
if (env > env_data)
++env;
/*
* Overflow when:
* "name" + "=" + "val" +"\0\0" > ENV_SIZE - (env-env_data)
*/
len = strlen(name) + 2;
/* add '=' for first arg, ' ' for all others */
for (i=2; i<argc; ++i) {
len += strlen(argv[i]) + 1;
}
if (len > (&env_data[ENV_SIZE]-env)) {
printf ("## Error: environment overflow, \"%s\" deleted\n", name);
return 1;
}
while ((*env = *name++) != '\0')
env++;
for (i=2; i<argc; ++i) {
char *val = argv[i];
*env = (i==2) ? '=' : ' ';
while ((*++env = *val++) != '\0')
;
}
/* end is marked with double '\0' */
*++env = '\0';
/* Update CRC */
env_crc_update ();
/*
* Some variables should be updated when the corresponding
* entry in the enviornment is changed
*/
if (strcmp(argv[1],"ethaddr") == 0) {
char *s = argv[2]; /* always use only one arg */
char *e;
for (i=0; i<6; ++i) {
bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
if (s) s = (*e) ? e+1 : e;
}
#ifdef CONFIG_NET_MULTI
eth_set_enetaddr(0, argv[2]);
#endif
return 0;
}
if (strcmp(argv[1],"ipaddr") == 0) {
char *s = argv[2]; /* always use only one arg */
char *e;
unsigned long addr;
bd->bi_ip_addr = 0;
for (addr=0, i=0; i<4; ++i) {
ulong val = s ? simple_strtoul(s, &e, 10) : 0;
addr <<= 8;
addr |= (val & 0xFF);
if (s) s = (*e) ? e+1 : e;
}
bd->bi_ip_addr = htonl(addr);
return 0;
}
if (strcmp(argv[1],"loadaddr") == 0) {
load_addr = simple_strtoul(argv[2], NULL, 16);
return 0;
}
#if defined(CONFIG_CMD_NET)
if (strcmp(argv[1],"bootfile") == 0) {
copy_filename (BootFile, argv[2], sizeof(BootFile));
return 0;
}
#endif
#ifdef CONFIG_AMIGAONEG3SE
if (strcmp(argv[1], "vga_fg_color") == 0 ||
strcmp(argv[1], "vga_bg_color") == 0 ) {
extern void video_set_color(unsigned char attr);
extern unsigned char video_get_attr(void);
video_set_color(video_get_attr());
return 0;
}
#endif /* CONFIG_AMIGAONEG3SE */
return 0;
}
saveenv
int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
extern char * env_name_spec;
printf ("Saving Environment to %s...\n", env_name_spec);
return (saveenv() ? 1 : 0);
}
int saveenv(void)
{
#if defined(CONFIG_S5PC100) || defined(CONFIG_S5PC110) || defined(CONFIG_S5P6442)
if (INF_REG3_REG == 2)
saveenv_nand();
else if (INF_REG3_REG == 3)
saveenv_movinand();
else if (INF_REG3_REG == 1)
saveenv_onenand();
else if (INF_REG3_REG == 4)
saveenv_nor();
#elif defined(CONFIG_SMDK6440)
if (INF_REG3_REG == 3)
saveenv_nand();
else if (INF_REG3_REG == 4 || INF_REG3_REG == 5 || INF_REG3_REG == 6)
saveenv_nand_adv();
else if (INF_REG3_REG == 0 || INF_REG3_REG == 1 || INF_REG3_REG == 7)
saveenv_movinand();
#else // others
if (INF_REG3_REG == 2 || INF_REG3_REG == 3)
saveenv_nand();
else if (INF_REG3_REG == 4 || INF_REG3_REG == 5 || INF_REG3_REG == 6)
saveenv_nand_adv();
else if (INF_REG3_REG == 0 || INF_REG3_REG == 7)
saveenv_movinand();
else if (INF_REG3_REG == 1)
saveenv_onenand();
#endif
else
printf("Unknown boot device\n");
return 0;
}
int saveenv_movinand(void)
{
#if defined(CONFIG_CMD_MOVINAND)
movi_write_env(virt_to_phys((ulong)env_ptr));
puts("done\n");
return 1;
#else
return 0;
#endif /* CONFIG_CMD_MOVINAND */
}
void movi_write_env(ulong addr)
{
movi_write(raw_area_control.image[2].start_blk,
raw_area_control.image[2].used_blk, addr);
}
typedef struct raw_area {
uint magic_number; /* to identify itself */
uint start_blk; /* compare with PT on coherency test */
uint total_blk;
uint next_raw_area; /* should be sector number */
char description[16];
member_t image[15];
} raw_area_t;
raw_area_control是uboot中规划iNnad/SD卡的原始分区表
getenv和getenv_r
getenv不可重入,getenv_r可重入
getenv函数是返回环境变量在DDR的地址,getenv_r复制DDR环境变量给buf,getenv_r更安全
/************************************************************************
* Look up variable from environment,
* return address of storage for that variable,
* or NULL if not found
*/
char *getenv (char *name)
{
int i, nxt;
WATCHDOG_RESET();
for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
int val;
for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
if (nxt >= CFG_ENV_SIZE) {
return (NULL);
}
}
if ((val=envmatch((uchar *)name, i)) < 0)
continue;
return ((char *)env_get_addr(val));
}
return (NULL);
}
int getenv_r (char *name, char *buf, unsigned len)
{
int i, nxt;
for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
int val, n;
for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
if (nxt >= CFG_ENV_SIZE) {
return (-1);
}
}
if ((val=envmatch((uchar *)name, i)) < 0)
continue;
/* found; copy out */
n = 0;
while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0')
;
if (len == n)
*buf = '\0';
return (n);
}
return (-1);
}
iNand/SD驱动(start_armboot)
cpu目录下驱动相关文件用于初始化soc内部关于iNand/SD控制器,drivers下用于初始化iNand/SD的内部控制器
mmc_initialize(uboot/drivers/mmc/mmc.c)
int mmc_initialize(bd_t *bis)
{
struct mmc *mmc;
int err;
INIT_LIST_HEAD(&mmc_devices);
cur_dev_num = 0;
if (board_mmc_init(bis) < 0)
cpu_mmc_init(bis);
#if defined(DEBUG_S3C_HSMMC)
print_mmc_devices(',');
#endif
#ifdef CONFIG_CHECK_X210CV3
mmc = find_mmc_device(1);//lqm
#else
mmc = find_mmc_device(0);
#endif
if (mmc) {
err = mmc_init(mmc);
if (err)
err = mmc_init(mmc);
if (err) {
printf("Card init fail!\n");
return err;
}
}
printf("%ldMB\n", (mmc->capacity/(1024*1024/(1<<9))));
return 0;
}
int cpu_mmc_init(bd_t *bis)
{
#ifdef CONFIG_S3C_HSMMC
setup_hsmmc_clock();
setup_hsmmc_cfg_gpio();
return smdk_s3c_hsmmc_init();
#else
return 0;
#endif
}
int smdk_s3c_hsmmc_init(void)
{
......
#ifdef USE_MMC0
err = s3c_hsmmc_initialize(0);
if(err)
return err;
#endif
......
#ifdef USE_MMC2
err = s3c_hsmmc_initialize(2);
if(err)
return err;
#endif
......
}
static int s3c_hsmmc_initialize(int channel)
{
struct mmc *mmc;
mmc = &mmc_channel[channel];
sprintf(mmc->name, "S3C_HSMMC%d", channel);
mmc->priv = &mmc_host[channel];
mmc->send_cmd = s3c_hsmmc_send_command;
mmc->set_ios = s3c_hsmmc_set_ios;
mmc->init = s3c_hsmmc_init;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
#if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)
mmc->host_caps |= MMC_MODE_8BIT;
#endif
mmc->f_min = 400000;
mmc->f_max = 52000000;
mmc_host[channel].clock = 0;
switch(channel) {
case 0:
mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE;
break;
case 1:
mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_1_BASE;
break;
case 2:
mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE;
break;
#ifdef USE_MMC3
case 3:
mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_3_BASE;
break;
#endif
default:
printk("mmc err: not supported channel %d\n", channel);
}
return mmc_register(mmc);
}
struct mmc {
struct list_head link;
char name[32];
void *priv;
uint voltages;
uint version;
uint f_min;
uint f_max;
int high_capacity;
uint bus_width;
uint clock;
uint card_caps;
uint host_caps;
uint ocr;
uint scr[2];
uint csd[4];
uint cid[4];
ushort rca;
uint tran_speed;
uint read_bl_len;
uint write_bl_len;
u32 capacity;
struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */
block_dev_desc_t block_dev;
int (*send_cmd)(struct mmc *mmc,
struct mmc_cmd *cmd, struct mmc_data *data);
void (*set_ios)(struct mmc *mmc);
int (*init)(struct mmc *mmc);
};
setup_hsmmc_clock初始化SoC中MMC控制器时钟
setup_hsmmc_cfg_gpio配置SoC中MMC控制器GPIO
smdk_s3c_hsmmc_init通过USE_MMCx来调用s3c_hsmmc_initialize函数
s3c_hsmmc_initialize定义并且实例化struct mmc类型对象(成员为驱动相关配置)
mmc_register进行mmc设备的注册.即将struct mmc使用链表连接到mmc_devices全局变量中
find_mmc_device
struct mmc *find_mmc_device(int dev_num)
{
struct mmc *m;
struct list_head *entry;
list_for_each(entry, &mmc_devices) {
m = list_entry(entry, struct mmc, link);
if (m->block_dev.dev == dev_num)
return m;
}
printf("MMC Device %d not found\n", dev_num);
return NULL;
}
通过mmc设备编号在系统中查找对应mmc设备
mmc_init
int mmc_init(struct mmc *host)
{
int err;
err = host->init(host);
if (err)
return err;
/* Reset the Card */
err = mmc_go_idle(host);
if (err)
return err;
/* Test for SD version 2 */
err = mmc_send_if_cond(host);
/* Now try to get the SD card's operating condition */
err = mmc_send_app_op_cond(host);
/* If the command timed out, we check for an MMC card */
if (err == TIMEOUT) {
err = mmc_send_op_cond(host);
if (err)
return UNUSABLE_ERR;
} else
if (err)
return UNUSABLE_ERR;
return mmc_startup(host);
}
mmc卡初始化,通过向mmc卡发送命令码初始化SD卡/iNand内部控制器
demo:
自定义uboot命令
cmd_author.c
#include <common.h>
#include <command.h>
int do_author (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
if(argc ==2)
{
if(!strcmp(argv[1],"1"))
{
printf("uboot community\n");
}
else if(!strcmp(argv[1],"2"))
{
printf("blog.csdn.cxb\n");
}
else
{
printf("%s\n",cmdtp->help);
}
}
else
{
printf("%s\n",cmdtp->help);
}
return 0;
}
U_BOOT_CMD(
author, 2, 1, do_author,
"author - author 1/2",
"author - author 1/2"
);
添加流程
cd uboot/common/
vim cmd_author.c
vim Makefile
COBJS-y += cmd_author.o
cd ..
./mk &>/dev/null &
cd sd_fusing
./sd_fusing3.sh /dev/sdb
结果示例: