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

原创 2015年09月06日 16:31:15

写在前头

*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个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的做法,这里就不再赘述.

参考

暂无

Linux u-boot加载过程 ----基于freescale i.MX6

转自 http://blog.csdn.net/njuitjf/article/details/20563867 这篇文章让我明白了imx6 内存配置文件是怎么被调用执行的,原来是被rom 第一步就调...
  • lqxandroid2012
  • lqxandroid2012
  • 2017-07-27 17:47:27
  • 627

freescale imx6 u-boot

1. git clone git://git.freescale.com/imx/uboot-imx.git 2.
  • mounter625
  • mounter625
  • 2014-10-30 14:49:29
  • 2872

飞思卡尔IMX6修改uboot默认启动参数

硬件平台:飞思卡尔IMX6 内核版本:kernel3.0.35 问题来源: 开发板的默认显示方式是FPC接口800*480的屏,本项目中用到的屏是工业级的1024*768接口的LVDS屏...
  • dddxxxx
  • dddxxxx
  • 2016-08-26 21:52:47
  • 3233

[IMX6Q]uboot_v2015.04编译流程分析

执行生成.config文件 #make mx6qecovacsandroid_configMakefile: %config: scripts_basic outputmakefile FORCE ...
  • kris_fei
  • kris_fei
  • 2016-01-18 11:36:02
  • 3628

IMX6Solo启动流程-从Uboot到kernel 下

分析bootcmd的执行流程
  • baicaiaichibaicai
  • baicaiaichibaicai
  • 2015-09-01 10:25:33
  • 1951

Uboot启动流程分析

boot是嵌入式系统中最常用的bootloader,这里我们以s3c2410为例分析一下uboot的启动流程。首先通过uboot的链接文件,我们可以看到uboot运行是执行的第一段代码在start.S...
  • farsight2009
  • farsight2009
  • 2010-07-21 15:42:00
  • 1478

IMX6Solo启动流程-从上电到Uboot

RIotBoard开发板/i.MX6 Solo的启动流程,从上电到内核。
  • baicaiaichibaicai
  • baicaiaichibaicai
  • 2015-08-25 17:30:17
  • 6890

[IMX6Q]u-boot启动kernel流程

u-boot版本:v2009.08 u-boot利用了env里的cmd来实现调用boot linux的接口, 效果等同于在u-boot中敲"booti xxx..." start_armboot...
  • kris_fei
  • kris_fei
  • 2016-01-07 15:49:38
  • 2532

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

新建一条Uboot命令
  • baicaiaichibaicai
  • baicaiaichibaicai
  • 2015-09-06 16:31:15
  • 1165

飞思卡尔IMX6修改uboot默认启动参数

硬件平台:飞思卡尔IMX6 内核版本:kernel3.0.35 问题来源: 开发板的默认显示方式是FPC接口800*480的屏,本项目中用到的屏是工业级的1024*768接口的LVDS屏,更换屏之...
  • BorntoX
  • BorntoX
  • 2016-07-15 14:59:30
  • 3713
收藏助手
不良信息举报
您举报文章:IMX6Solo启动流程 外传-新建一条Uboot命令
举报原因:
原因补充:

(最多只允许输入30个字)