IMX6Solo启动流程 外传-新建一条Uboot命令

来源:互联网 发布:js点击空白处触发事件 编辑:程序博客网 时间:2024/05/16 15:01

写在前头

*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个QQ群82642304,欢迎加入!
*.目的:整理一下RIotBoard开发板的启动流程,对自己的所学做一个整理总结,本系列Uboot代码基于2009.08版。
*.备注:整个系列只是对我所学进行总结,记录我认为是关键的点,另我能力有限,难免出现疏漏错误,如果读者有发现请多指正,以免我误导他人!


原理

在《IMX6Solo启动流程-从Uboot到kernel 上》中我们讲到了Uboot命令是通过宏U_BOOT_CMD来定义的.所以新建一条命令实际上就是定义一个宏的过程.
在新建一条命令之前,我们先要区分一下新建的命令是属于通用的还是专用的,所谓通用就是你的命令与具体的硬件无关,例如tftp命令,bootm命令等,专用的就是你的命令只能在你的硬件上面跑.
Uboot的命令一般在两个地方定义,一个是common目录下,在这里面定义的一般都是通用的命令,另外一个就是在board/xxx目录下,定义的就是专用的,当然这不是强制要求,只是一个建议,这样定义命令能够让逻辑分开.
我在每次更新Uboot或者内核的时候都要执行

tftp u-boot.bin
mmc dev 3
mmc erase 0 400
mmc write ${loadaddr} 0 400

对于我这种懒人来说,复制粘帖这几行都是一件繁琐的事情.所以就想新建一条命令,能够一条命令执行以上四个步骤.
在RIotBoard开发板上,存储设备是emmc,即port 3,下载烧写地址和长度都是固定的,所以这是一条专用的命令.当然你也可以将这些数据以参数的形式传给命令,将命令拓展成通用的.其实都一样.
首先在board/freescale/mx6q_riot/目录下新建cmd_update.c,定义命令

U_BOOT_CMD(    uduboot,    2,    1,    do_uduboot,    "download uboot from tftp,then update it",    "uduboot [uboot file name]");U_BOOT_CMD(    udkernel,    2,    1,    do_udkernel,    "download kernel from tftp,then update it",    "udkernel [kernel file name]");

然后实现函数do_uduboot和do_uduboot.接下来修改board/freescale/mx6q_riot/Makefile,将cmd_update.c编译进去.

COBJS   := $(BOARD).o cmd_update.o

在COBJS中增加 cmd_update.o
重新编译Uboot并下载烧写,在Uboot的命令交互模式下就可以看到新加两条命令uduboot和udkernel.
另:使用tftp需要配置Uboot的环境变量ipaddr和serverip,每次烧写Uboot,之前配置的环境变量值都会被恢复默认值,所以可以通过修改ipaddr和serverip的默认值,后续烧写Uboot就无需修改IP地址.


源码

#include <common.h>#include <command.h>#include <asm/io.h>#include <mmc.h>#include <net.h>#include <malloc.h>#define UBOOT_FILE_OFFSET   1024#define MMC_PAGE_SIZE       512extern ulong TftpRRQTimeoutMSecs;extern int TftpRRQTimeoutCountMax;extern ulong load_addr;extern enum boot_device get_boot_device(void);extern int get_mmc_env_devno(void);/* follow function copy from $(TOPDIR)/common/update.c */static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr){    int size, rv;    ulong saved_timeout_msecs;    int saved_timeout_count;    char *saved_netretry, *saved_bootfile;    rv = 0;    /* save used globals and env variable */    saved_timeout_msecs = TftpRRQTimeoutMSecs;    saved_timeout_count = TftpRRQTimeoutCountMax;    saved_netretry = strdup(getenv("netretry"));    saved_bootfile = strdup(BootFile);    /* set timeouts for auto-update */    TftpRRQTimeoutMSecs = msec_max;    TftpRRQTimeoutCountMax = cnt_max;    /* we don't want to retry the connection if errors occur */    setenv("netretry", "no");    /* download the update file */    load_addr = addr;    copy_filename(BootFile, filename, sizeof(BootFile));    size = NetLoop(TFTP);    if (size < 0)        rv = 1;    else if (size > 0)        flush_cache(addr, size);    /* restore changed globals and env variable */    TftpRRQTimeoutMSecs = saved_timeout_msecs;    TftpRRQTimeoutCountMax = saved_timeout_count;    setenv("netretry", saved_netretry);    if (saved_netretry != NULL)        free(saved_netretry);    if (saved_bootfile != NULL) {        copy_filename(BootFile, saved_bootfile, sizeof(BootFile));        free(saved_bootfile);    }    return rv;}int DownloadAndUpdate(char * filename,unsigned int maxsize,                      unsigned int startblk,unsigned int fileoffset){    char * serverIP = getenv("serverip");    struct mmc * mmc = NULL;    block_dev_desc_t * mmc_dev = NULL;    char * s;    ulong addr;    uint boot_devno;    unsigned int filesize;    unsigned int block;    if (NULL == serverIP) {        printf("error: not found tftp server IP\n");        return -1;    }    /* get load address of downloaded update file */    if ((s = getenv("loadaddr")) != NULL){        addr = simple_strtoul(s, NULL, 16);    }else{        printf("error: not found $(loadaddr)\n");        return -1;    }    if (MMC_BOOT != get_boot_device()) {        printf("error: only support MMC boot dev\n");        return -1;    }    printf("download %s from %s\n",filename,serverIP);    if(update_load(filename,100,10,addr)){        printf("error: download failure\n");        return -1;    }else if (NULL == (s = getenv("filesize"))) {        printf("error: download failure,not found $(filesize)\n");        return -1;    }else{        filesize = simple_strtol(s,NULL,16);        if (filesize < maxsize) {            printf("download success,file length %d(0x%x)\n", filesize, filesize);         }else{            printf("error: download failure,$(filesize) bigger then 1M\n");            return -1;        }    }    block = (filesize + MMC_PAGE_SIZE - 1)/MMC_PAGE_SIZE;    boot_devno = readl(SRC_BASE_ADDR + 0x4);    /* BOOT_CFG2[3] and BOOT_CFG2[4] */    boot_devno = (boot_devno & 0x00001800) >> 11;    if (boot_devno >= CONFIG_SYS_FSL_USDHC_NUM) {        printf("error: not such mmc dev %d\n",boot_devno);        return -1;    }else{        printf("boot dev is MMC%d\n",boot_devno);    }    if(NULL == (mmc = find_mmc_device(boot_devno))){        printf("Can't find mmc devno %d\n",boot_devno);        return -1;    }    mmc_init(mmc);    if (NULL == (mmc_dev = mmc_get_dev(boot_devno))) {        printf("mmc init failure %d\n",boot_devno);        return -1;    }    if (block != mmc_dev->block_erase(boot_devno,startblk,block)) {        printf("error: erase %d,%d failure\n",startblk,block);        return -1;    }else{        printf("erase %d,%d\n",startblk,block);    }    if (block != mmc_dev->block_write(boot_devno,startblk,block,(void *)(addr + fileoffset))) {        printf("error: write %d,%d failure\n",startblk,block);        return -1;    }else{        printf("write %d,%d,0x%x\n",startblk,block,addr + fileoffset);    }    printf("update %s success\n",filename);    return 0; }int do_uduboot ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){    char * filename = "u-boot.bin";    if (argc > 1) {        filename = argv[1];    }    return DownloadAndUpdate(filename,0x100000,UBOOT_FILE_OFFSET/MMC_PAGE_SIZE,UBOOT_FILE_OFFSET);};int do_udkernel ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){    char * filename = "uImage";    if (argc > 1) {        filename = argv[1];    }    return DownloadAndUpdate(filename,0x800000,0x800,0);};U_BOOT_CMD(    uduboot,    2,    1,    do_uduboot,    "download uboot from tftp,then update it",    "uduboot [uboot file name]");U_BOOT_CMD(    udkernel,    2,    1,    do_udkernel,    "download kernel from tftp,then update it",    "udkernel [kernel file name]");

总结

只要了解U_BOOT_CMD宏的原理之后,新建一条命令就十分简单。
另:上述的功能也可以通过将多条命令用分号隔开,保存到一个环境变量中,然后通过run命令来执行,达到一样的效果。类似bootcmd的做法,这里就不再赘述.

参考

暂无

0 0
原创粉丝点击