[IMX6] Defining A U-Boot Command

Compiling a user uboot command

1. Function Overview

I wish to boot a partition that can be decided in the U-Boot stage. The process is highlighted below:

I have to compose the U-Boot independent application to implement the logic marked red.

2. U-Boot independent APP

The U-Boot provides a console we can interact with. This section will introduce how to add an independent command to the U-Boot source code project. In the U-Boot project, each U-Boot provided command is defined by U_BOOT_CMD macro in 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}

Attributes:

  • name: The command name;

  • maxargs: The maximum of the inputted arguments;

  • command: The C function is mapped to the command;

  • usage: Usage message;

  • ...

2.1 Code Base

Assuming the command name is utils_load

Add obj-y += utils_load.o to Makefile in common directory.

Create utils_load.c file in common directory.

The content of utils_load.c file is:

#include <common.h>
#include <command.h>
#include <linux/stddef.h>

int do_utils_load(cmd_tbl_t *cmdtp, int flag, int argc, char* const argv[])
{
    int ret = 0;
    int i = 0;

    printf("[INFO] The input is %d\n", argc);
    for (i = 0; i < argc; i ++) {
        printf("[INFO] the argv[%d] is %s\n", i, argv[i]);
    }

finish:
    return ret;
}

U_BOOT_CMD(
    utils_load,
    5,
    1,
    do_utils_load,
    "format : utils_load address",
    "example: utils_load 0x80000000"
);

Then build the U-Boot by

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

in imx6 platform.

2.2 Judging Secure Boot

https://github.com/carloscn/imx-uboot/commit/916419376b988d1a16461810bf358f94ca990e0f#diff-d397fabf5af5abbfeebdcba5c3b68879fb33e5bd432ea70a75e26dbf850a848b

There are two versions of NXP S32G SoC:

  • Rev 1.0

  • Rev 2.0 (The HSE is enabled)

The Rev 1.0 hasn't HSE, while the Rev 2.0 has enabled the HSE.

We can use the version information to distinguish if the SoC has been enabled HSE.

The Secure Boot can be distinguished by DDR storage:

3. Examples

Here are some examples of common U-Boot independent applications at https://cloud.tencent.com/developer/article/1974907

3.1 BEE

#include <common.h>
#include <command.h>
#define GPD0CON		(*(volatile unsigned int *)0x114000A0) //定义蜂鸣器IO口的地址
#define GPD0DAT		(*(volatile unsigned int *)0x114000A4)

int do_beep( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	GPD0CON&=~(0xf<<0);
	GPD0CON|=(0x1<<0);
	
	if(!strcmp(argv[1],"on"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
		{
			GPD0DAT|=(1<<0);	
		}
	if(!strcmp(argv[1],"off"))//strcmp是比较字符串的函数,如果传进来的是off,就关闭蜂鸣器
		{
		 	GPD0DAT&=~(1<<0);	
		}
	else
		printf("Usage:beep <on|off>!\n"); //如果不是on 也不是off  就输出提示
}


U_BOOT_CMD( 
	beep,    //在u-boot命令行里显示的命令名称
	2,       //形参最大个数
	1,       //重复次数 (按下回车--自动执行上一次命令)
	do_beep, //命令执行函数(回调函数--)
	"传参格式: beep <on|off>",   //用法提示
	"传承示例:beep on 或者 beep off......."  //帮助命令的提示信息
);

3.2 Control LEDs

#include <common.h>
#include <command.h>

/* 1、LED灯接口配置寄存器 */
#define GPM4CON     (*(volatile unsigned int *)0x110002E0)
#define GPM4DAT     (*(volatile unsigned int *)0x110002E4)

int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	// led 1 on
	// led 1 off
	GPM4CON &= ~(0xf << 0 * 4);    //清除寄存器1
  GPM4CON |=  (1   << 0 * 4);    //输出模式
  
  GPM4CON &= ~(0xf << 1 * 4);    //清除寄存器2
  GPM4CON |=  (1   << 1 * 4);    //输出模式
  
  GPM4CON &= ~(0xf << 2 * 4);    //清除寄存器3
  GPM4CON |=  (1   << 2 * 4);    //输出模式
  
  GPM4CON &= ~(0xf << 3 * 4);    //清除寄存器4
  GPM4CON |=  (1   << 3 * 4);    //输出模式
  
  
  /*第一盏灯*/	
	if(!strcmp(argv[1],"1"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 0);      //点亮第一个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 0;          //关闭第一个灯 
			}
		}
		
		/*第二盏灯*/	
	else if(!strcmp(argv[1],"2"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 1);      //点亮第二个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 1;          //关闭第二个灯 
			}
		}
	
		/*第三盏灯*/	
	else if(!strcmp(argv[1],"3"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 2);      //点亮第三个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 2;          //关闭第三个灯 
			}
		}
		
	/*第四盏灯*/	
	else if(!strcmp(argv[1],"4"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 3);      //点亮第四个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 3;          //关闭第四个灯 
			}
		}

	else
		printf("Usage:led <1~4> <on|off>\n"); //如果不是on 也不是off  就输出提示
}


U_BOOT_CMD( 
	led,     //在u-boot命令行里显示的命令名称
	3,       //形参最大个数
	1,       //重复次数
	do_led,  //命令执行函数
	"user: LED count <on|off>",   //用法提示
	"cmd : (1)led  1 on (2)led 1 off...."  //帮助命令的提示信息
);

3.3 movi

#include <common.h>
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <nand.h>
#include <onenand_uboot.h>
#include <mmc.h>
#include <asm/arch/cpu.h>
#include <asm/arch/movi_partition.h>

int do_mymovi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	int r_cnt,w_cnt;
   /*1. 查找设备0-SD卡*/
	struct mmc *mmc0 = find_mmc_device(0);
	if(mmc0==NULL)
	{
		printf("设备0查找失败!\n");
		return 0;
	}
	/*2. 查找设备1--MMC*/
	struct mmc *mmc1 = find_mmc_device(1);
	if(mmc1==NULL)
	{
		printf("设备1查找失败!\n");
		return 0;
	}
	/*3. 初始化SD卡*/
    mmc_init(mmc0); /*设备0初始化--SD卡*/
  
  /*4. 初始化EMMC*/
  	mmc_init(mmc1); /*设备1初始化--EMMC卡*/ 
	emmc_boot_open(mmc1); /*设备1打开---EMMC*/
	
	/*5. 烧写数据*/
		/*5.1 BL1*/
		r_cnt=movi_read(0,1,16,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,0,16,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("BL1_r_cnt=%d\n",r_cnt);
		printf("BL1_w_cnt=%d\n",w_cnt);
  	
  	/*5.2 BL2*/
  	    r_cnt=movi_read(0,17,32,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,16,32,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("BL2_r_cnt=%d\n",r_cnt);
		printf("BL2_w_cnt=%d\n",w_cnt);

	  /*5.3 UBOOT\这里最好使用malloc申请空间,太大的地址可能会被其他数据覆盖掉*/
  		r_cnt=movi_read(0,49,656,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,48,656,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("UBOOT_r_cnt=%d\n",r_cnt);
		printf("UBOOT_w_cnt=%d\n",w_cnt);
		
		/*5.4 TZSW*/
  		r_cnt=movi_read(0,705,320,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,704,320,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("TZSW_r_cnt=%d\n",r_cnt);
		printf("TZSW_w_cnt=%d\n",w_cnt);
		
		/*5.5 Linux内核*/
  		r_cnt=movi_read(0,1057,12288,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,1057,12288,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("Linux内核_r_cnt=%d\n",r_cnt);
		printf("Linux内核_w_cnt=%d\n",w_cnt);
  	emmc_boot_close(mmc1); //关闭EMMC
	
	/*5.5 环境变量*/
	r_cnt=movi_read(0,1025,32,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
	w_cnt=movi_write(1,1025,32,(void*)0x40008000);//将读出的数据写入到EMMC
	printf("环境变量_r_cnt=%d\n",r_cnt);
	printf("环境变量_w_cnt=%d\n",w_cnt);
	printf("环境变量拷贝成功!\n");
	return 0;
}

U_BOOT_CMD(
	mymovi,    /*命令的名称*/
	1,          /*形参的最大个数*/
	0,          /*命令执行重复次数*/
	do_mymovi,/*命令处理函数*/
	"将SD卡的BL1/BL2/uboot/签名文件/内核拷贝到EMMC", /*简短提示*/
	"\n"
	"将SD卡的BL1/BL2/uboot/签名文件/内核拷贝到EMMC\n" /*完整提示*/
	"注意: 该命令在开发板以SD卡启动方式时运用\n"
);

3.4 uboot env copying

#include <common.h>
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <nand.h>
#include <onenand_uboot.h>
#include <mmc.h>
#include <asm/arch/cpu.h>
#include <asm/arch/movi_partition.h>

/*
//以MMC方式启动,运行下面命令即可完成环境变量拷贝(SD-->EMMC)
mmc read 1 40000000 401 20
mmc write 0 40000000 401 20

//以SD方式启动,运行下面命令即可完成环境变量拷贝 (SD--->EMMC)
mmc read 0 40000000 401 20
mmc write 1 40000000 401 20
*/
int do_copyenv(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	int r_cnt,w_cnt;
    mmc_init(find_mmc_device(0)); /*设备0初始化--SD卡*/
  	mmc_init(find_mmc_device(1)); /*设备1初始化--EMMC卡*/ 

	/*5.5 环境变量*/
	r_cnt=movi_read(0,1025,32,(void*)0x40000000); //读出SD卡里存放到所有数据到DDR指定地址
	w_cnt=movi_write(1,1025,32,(void*)0x40000000);//将读出的数据写入到EMMC
	printf("环境变量_r_cnt=%d\n",r_cnt);
	printf("环境变量_w_cnt=%d\n",w_cnt);
	printf("环境变量拷贝成功!\n");
	return 0;
}


U_BOOT_CMD(
	copyenv,    /*命令的名称*/
	1,          /*形参的最大个数*/
	0,          /*命令执行重复次数*/
	do_copyenv,/*命令处理函数*/
	"将SD卡的环境变量拷贝到EMMC", /*简短提示*/
	"\n"
	"将SD卡的环境变量拷贝到EMMC\n" /*完整提示*/
	"注意: 该命令在开发板以SD卡启动方式时运用\n"
);

最后更新于