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

写在前头

*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个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       512


extern 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值