<Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分)

article/2025/10/6 5:36:27

<Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分)

第一部分链接:系统移植-之-uboot移植第一部分

第一部分主要讲解了,uboot移植过程中使用的一些工具的安装,以及测试nxp远程uboot,是否能再正点原子Linux开发板正常运行。

本部分主要讲的是,将nxp原厂uboot,移植,适配到正点原子的linux开发板上。由于NXP官方demo板和正点原子linux开发板,在硬件上存在差异,所以,需要修改NXP原厂uboot的一些内容,才能适配正点原子linux开发板,这个过程叫移植。接下来就讲解,作者移植过程的一些记录。

本文参考正点原子linux驱动开发手册,如有不详之处,可查找正点原子官方资料,或联系作者。
联系方式QQ:759521350

一、移植开发板对应的文件
在第一部分操作后,开始移植到正点原子linux开发板,主要涉及部分文件内容的修改等,具体如。
1、将第一部分解压后的文件夹复制一份,并命令“uboot_onefu”,如下图:
命令:cp uboot-imx-rel_imx_4.1.15_2.1.0_ga uboot_onefu -rf
在这里插入图片描述
2、添加开发板默认配置文件
进入“uboot_onefu/configs”,复制“mx6ull_14x14_evk_emmc_defconfig”,并将复制后的文件命名为“mx6ull_onefu_emmc_defconfig”。相关命令如下:

cd uboot_onefu/configs/
cp mx6ull_14x14_evk_emmc_defconfig  mx6ull_onefu_emmc_defconfig

在这里插入图片描述
将“mx6ull_onefu_emmc_defconfig”中的内容修改成下面的:

CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_onefu_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ONEFU_EMMC=y
CONFIG_CMD_GPIO=y

可看出,只对第1行和第4行做了修改。

3、添加开发板对应的头文件
在目录“include/configs”下添加使用的Linux开发板对应的头文件。进入“uboot_onefu/include/configs”,复制“mx6ullevk.h”,并将复制后的文件命名为“mx6ull_onefu_emmc.h”。相关命令如下:

 cd include/configs/cp mx6ullevk.h  mx6ull_onefu_emmc.h

在这里插入图片描述
将“mx6ull_onefu_emmc.h”中的:

#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H

更改为:

#ifndef __MX6ULL_ONEFU_EMMC_CONFIG_H
#define __MX6ULL_ONEFU_EMMC_CONFIG_H

mx6ull_onefu_emmc.h里面有很多宏定义,这些宏定义基本用于配置uboot,也有一些I.MX6ULL的配置项目。如果我们自己要想使能或者禁止uboot的某些功能,那就在mx6ull_onefu_emmc.h里面做修改即可。mx6ull_onefu_emmc.h里面的内容比较多,可以去掉一些用不到的配置;这里作者不做删减。

4、添加开发板对应的板极文件夹
boot中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等等。NXP的I.MX系列芯片的所有板级文件夹都存放在board/freescale目录下,在这个目录下有个名为mx6ullevk的文件夹,这个文件夹就是NXP官方I.MX6ULL EVK开发板的板级文件夹。复制mx6ullevk,将其重命名为mx6ull_onefu_emmc,命令如下:

cd board/freescale/
cp mx6ullevk/ -r mx6ull_onefu_emmc

在这里插入图片描述
接下来对“mx6ull_onefu_emmc”目录下的文件进行一些修改
(1)进入“mx6ull_onefu_emmc”将其中的mx6ullevk.c文件重命名为mx6ull_onefu_emmc.c,命令如下:

cd board/freescale/mx6ull_onefu_emmc/
mv mx6ullevk.c  mx6ull_onefu_emmc.c

在这里插入图片描述

(2)修改该目录下的Makefile文件,修改后如下:

# (C) Copyright 2015 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier:	GPL-2.0+
#obj-y  := mx6ull_onefu_emmc.oextra-$(CONFIG_USE_PLUGIN) :=  plugin.bin
$(obj)/plugin.bin: $(obj)/plugin.o$(OBJCOPY) -O binary --gap-fill 0xff $< $@

在这里插入图片描述
重点是第6行的obj-y,改为mx6ull_onefu_emmc.o,这样才会编译mx6ull_onefu_emmc.c这个文件。

(3)修改mx6ull_onefu_emmc目录下的imximage.cfg文件
将imximage.cfg中的下面一句:
PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
更改为:
PLUGIN board/freescale/mx6ull_onefu_emmc /plugin.bin 0x00907000
在这里插入图片描述
(4)修改mx6ull_onefu_emmc目录下的Kconfig文件
修改Kconfig文件,修改后的内容如下:

if TARGET_MX6ULL_ONEFU_EMMCconfig SYS_BOARDdefault "mx6ull_onefu_emmc"config SYS_VENDORdefault "freescale"config SYS_SOC default "mx6"config SYS_CONFIG_NAMEdefault "mx6ull_onefu_emmc"endif

在这里插入图片描述
(5)修改mx6ull_onefu_emmc目录下的MAINTAINERS文件
修改MAINTAINERS文件,修改后的内容如下:

MX6ULL_ONEFU_EMMC BOARD
M:	Peng Fan <peng.fan@nxp.com>
S:	Maintained
F:	board/freescale/mx6ull_onefu_emmc/
F:	include/configs/mx6ull_onefu_emmc.h

在这里插入图片描述
5、修改U-Boot图形界面配置文件
uboot是支持图形界面配置,修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的I.MX6UL的话,应该修改arch/arm/Kconfig这个文件),在207行加入如下内容:

config TARGET_MX6ULL_ONEFU_EMMCbool "Support mx6ull_onefu_emmc"select MX6ULLselect DMselect DM_THERMAL

在这里插入图片描述
末尾添加如下:

source "board/freescale/mx6ull_onefu_emmc/Kconfig"

在这里插入图片描述

至此,开发板对应名称的相关文件的已经添加到uboot中了,加下来编译这个新添加的开发板的uboot。

6、使用新添加的板子配置编译uboot

在uboot的跟目录“uboot_onefu”下创建名为mx6ull_onefu_emmc.sh的shell脚本,内容如下:

#!/bin/bash
#清理工程
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
#执行配置uboot
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_onefu_emmc_defconfig
#执行编译
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16#注1: ARCH=arm  设置目标为arm架构
#注2: CROSS_COMPILE=arm-linux-gnueabihf-    指定编译工具链前缀
#注3: V=1  用于设置编译过程的信息输出级别
#注4-j16 使用16核编译uboot

在这里插入图片描述
给予“mx6ull_onefu_emmc.sh”,相关权限,并运行脚本,命令如下:

chmod 777 mx6ull_onefu_emmc.sh  //给予可执行权限
./mx6ull_onefu_emmc.sh			//运行脚本,编译uboot

编译结果如下:
在这里插入图片描述
7、烧写入SD卡,运行测试
烧写如下:
在这里插入图片描述
开发板设置为SD卡启动,将SD卡插入开发板,打开CRT,按下复位键,显示如下:
在这里插入图片描述
可以看出,此时的Board还是“MX6ULL 14x14 EVK”,因为我们参考的NXP官方的I.MX6ULL开发板来添加自己的开发板。如果接了LCD屏幕的话会发现LCD屏幕并没有显示NXP的logo,而且从图33.2.5.1可以看出此时的网络同样也没识别出来。前面已经说了,默认uboot中的LCD驱动和网络驱动在正点原子的I.MX6U-ALPHA开发板上是有问题的,因为NXP官方的开发板和正点原子的开发板,部分电路不同,所以需要修改。
接下来就是修改。

二、移植修改开发板对应的文件
1、LCD驱动修改
一般uboot中修改驱动基本都是在xxx.h和xxx.c这两个文件中进行的,xxx为板子名称,比如mx6ull_onefu_emmc.h和mx6ull_onefu_emmc.c这两个文件。
一般修改LCD驱动重点注意以下几点:
①、LCD所使用的GPIO,查看uboot中LCD的IO配置是否正确。 ②、LCD背光引脚GPIO的配置。
③、LCD配置参数是否正确。
正点原子的I.MX6U-ALPHA开发板LCD原理图和NXP官方I.MX6ULL开发板一致,也就是LCD的IO和背光IO都一样的,所以IO部分就不用修改了。需要修改的之后LCD参数,打开文件"board/freescale/mx6ull_onefu_emmc/mx6ull_onefu_emmc.c",找到"struct display_info_t const displays",修改后如下所示内容:

struct display_info_t const displays[] = {{.bus = MX6UL_LCDIF1_BASE_ADDR,.addr = 0,.pixfmt = 24,.detect = NULL,.enable	= do_enable_parallel_lcd,.mode	= {.name			= "TFT7016",.xres           = 1024,.yres           = 600,.pixclock       = 19531,.left_margin    = 140,		//HBPD.right_margin   = 160,		//HFPD.upper_margin   = 20,		//VBPD.lower_margin   = 12,		//VFBD.hsync_len      = 20,		//HSPW.vsync_len      = 3,		//VSPW.sync           = 0,.vmode          = FB_VMODE_NONINTERLACED
} } };

修改LCD参数时,根据所使用的LCD的具体参数信息修改,详细可参考对应LCD的开发手册。作者的LCD是正点原子配套LCD,7寸、1024x600。

将“include/configs/mx6ull_onefu_emmc.h”中所有的“panel=TFT43AB”更改为“panel=TFT7016”

修改完成以后重新编译一遍uboot并烧写到SD中启动。
重启以后LCD驱动一般就会工作正常了,LCD上回显示NXP的logo。但是有可能会遇到LCD并没有工作,还是黑屏,这是什么原因呢?在uboot命令模式输入“print”来查看环境变量panel的值,会发现panel的值要是TFT43AB(或其他的,反正不是TFT7016)。如下图:
在这里插入图片描述
这是因为之前有将环境变量保存到EMC中,uboot启动以后会先从EMMC中读取环境变量,如果EMMC中没有环境变量的话才会使用mx6ull_onefu_emmc.h中的默认环境变量。如果EMMC中的环境变量panel不等于TFT7016,那么LCD显示肯定不正常,我们只需要在uboot中修改panel的值为TFT7016即可,在uboot的命令模式下输入如下命令:

setenv panel TFT7016 
saveenv 

上述命令修改环境变量panel为TFT7016,然后保存,重启uboot,此时LCD驱动就工作正常了。如果LCD还是没有正常工作的,那就要检查自己哪里有没有改错,或者还有哪里没有修改。

2、网络驱动修改
正点原子使用的网络芯片和NXP使用的网络芯片不同。详细可查看正点原子Linux开发板原理图。
网络PHY地址修改:
首先修改uboot中的ENET1和ENET2的PHY地址和驱动,打开“include/configs/mx6ull_onefu_emmc.h”这个文件,找到325行处,修改后如下所示:

#ifdef CONFIG_CMD_NET
#define CONFIG_CMD_PING
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_MII
#define CONFIG_FEC_MXC
#define CONFIG_MII
#define CONFIG_FEC_ENET_DEV		1#if (CONFIG_FEC_ENET_DEV == 0)
#define IMX_FEC_BASE			ENET_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR          0x0
#define CONFIG_FEC_XCV_TYPE             RMII
#elif (CONFIG_FEC_ENET_DEV == 1)
#define IMX_FEC_BASE			ENET2_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR		0x1
#define CONFIG_FEC_XCV_TYPE		RMII
#endif
#define CONFIG_ETHPRIME			"FEC"#define CONFIG_PHYLIB
#define CONFIG_PHY_SMSC
#endif

在这里插入图片描述
删除uboot中74LV595的驱动代码
uboot中网络PHY芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开"board/freescale/mx6ull_onefu_emmc/mx6ull_onefu_emmc.c",找到如下代码:

#define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8)

修改后如下:

#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)

继续在mx6ull_onefu_emmc.c中找到如下代码,然后删除:

static iomux_v3_cfg_t const iox_pads[] = {/* IOX_SDI */MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),/* IOX_SHCP */MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),/* IOX_STCP */MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),/* IOX_nOE */MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

继续在mx6ull_onefu_emmc.c中找到函数iox74lv_init和iox74lv_set,并将这个两个函数全删除。

static void iox74lv_init(void)
{int i;gpio_direction_output(IOX_OE, 0);for (i = 7; i >= 0; i--) {gpio_direction_output(IOX_SHCP, 0);gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);udelay(500);gpio_direction_output(IOX_SHCP, 1);udelay(500);}
......省略/** shift register will be output to pins*/gpio_direction_output(IOX_STCP, 1);
};void iox74lv_set(int index)
{int i;for (i = 7; i >= 0; i--) {gpio_direction_output(IOX_SHCP, 0);if (i == index)gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);elsegpio_direction_output(IOX_SDI, seq[qn_output[i]][1]);udelay(500);gpio_direction_output(IOX_SHCP, 1);udelay(500);}
......省略/** shift register will be output to pins*/gpio_direction_output(IOX_STCP, 1);
};

在mx6ull_onefu_emmc.c中找到board_init函数,此函数是板子初始化函数,会被board_init_r调用,board_init函数内容如下:

int board_init(void)
{/* Address of boot parameters */gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));iox74lv_init();#ifdef CONFIG_SYS_I2C_MXCsetup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
#endif#ifdef	CONFIG_FEC_MXCsetup_fec(CONFIG_FEC_ENET_DEV);
#endif#ifdef CONFIG_USB_EHCI_MX6setup_usb();
#endif#ifdef CONFIG_FSL_QSPIboard_qspi_init();
#endif#ifdef CONFIG_NAND_MXSsetup_gpmi_nand();
#endifreturn 0;
}

删除imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads)); 和iox74lv_init();

至此,mx6ull_onefu_emmc.c中关于74LV595芯片的驱动代码都删除掉了。

添加I.MX6U-ALPHA开发板网络复位引脚驱动

在mx6ull_onefu_emmc.c中找到修改后如下代码所示:

static iomux_v3_cfg_t const fec1_pads[] = {MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
};static iomux_v3_cfg_t const fec2_pads[] = {MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

在这里插入图片描述
继续在文件mx6ull_onefu_emmc.c中找到函数setup_iomux_fec,修改后如下所示:

static void setup_iomux_fec(int fec_id)
{if (fec_id == 0){imx_iomux_v3_setup_multiple_pads(fec1_pads,ARRAY_SIZE(fec1_pads));gpio_direction_output(ENET1_RESET, 1);gpio_set_value(ENET1_RESET, 0);mdelay(20);gpio_set_value(ENET1_RESET, 1);}else{imx_iomux_v3_setup_multiple_pads(fec2_pads,ARRAY_SIZE(fec2_pads));gpio_direction_output(ENET2_RESET, 1);gpio_set_value(ENET2_RESET, 0);mdelay(20);gpio_set_value(ENET2_RESET, 1);}
}

在这里插入图片描述
修改drivers/net/phy/phy.c文件中的函数genphy_update_link
uboot中的LAN8720A驱动有点问题,打开文件drivers/net/phy/phy.c,找到函数genphy_update_link,这是个通用PHY驱动函数,此函数用于更新PHY的连接状态和速度。使用LAN8720A的时候需要在此函数中添加一些代码,修改后的函数genphy_update_link如下所示:

int genphy_update_link(struct phy_device *phydev)
{unsigned int mii_reg;#ifdef CONFIG_PHY_SMSCstatic int lan8720_flag = 0;int bmcr_reg = 0;if (lan8720_flag == 0) {bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) {udelay(100);}phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg); lan8720_flag = 1;}
#endif/** Wait if the link is up, and autonegotiation is in progress* (ie - we're capable and it's not done)*/mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);.....省略
}

至此 网络驱动复位引脚驱动修改完成。
修改完成以后重新编译一遍uboot并烧写到SD中启动。
测试
开发板链接电脑,并打开CRT,将开发板设置为SD启动,将SD卡插入开发板,并按下复位键,当CRT倒计时时,按下回车,使开发板运行在boot状态。
然后输入一下内容:

 setenv ipaddr 192.168.1.145		//设置本地开发板IPsetenv ethaddr 00:04:9f:04:2d:35	//设置MAC地址	setenv gatewayip 192.168.1.1    	//设置网关IPsetenv netmask 255.255.255.0		//设置DNSsetenv serverip 192.168.1.144		//设置服务器IP,这里用的时ubuntu,即虚拟机的IPsaveenv							//保存环境变量

完成后如下图所示:
在这里插入图片描述
上图中,红色部分是因为IP输入错误,然后输出提示,可以看出,当输出的IP格式错误时,uboot会有提示错误的功能。

接下来就ping一下主机ubuntu,输入命令:

ping 192.168.1.144

稍等一下,会有下图所示:
在这里插入图片描述
上图有“host 192.168.1.144 is alive”这句,说明ping主机成功,说明ENET2网络工作正常。再来测试一下ENET1的网络是否正常工作,打开mx6ull_onefu_emmc.h,将 CONFIG_FEC_ENET_DEV改为0,然后重新编译一下uboot并烧写到SD卡中重启,重启后设置IP后,重新ping主机,查看输出是否和上面一致,即可验证ENET1的网络了。

3、其它修改
在这里插入图片描述
开机后进入uboot后,CRT输出的提示有“Board: MX6ULL 14x14 EVK”,这句说的时板子的名称,那我们要更改为我们的开发板的名称。
打开"board/freescale/mx6ull_onefu_emmc/mx6ull_onefu_emmc.c",找到函数“checkboard”,将其内容更改后如下:

int checkboard(void)
{if (is_mx6ull_9x9_evk())puts("Board: MX6ULL 9x9 EVK\n");elseputs("Board: MX6ULL ONEFU EMMC\n");return 0;
}

修改完成以后重新编译uboot并烧写到SD卡中验证,uboot启动信息如下图所示:
在这里插入图片描述
至此uboot的驱动部分就修改完成了,uboot移植也完成了,uboot的最终目的就是启动Linux内核,所以需要通过启动Linux内核来判断uboot移植是否成功。在启动Linux内核之前我们先来学习两个重要的环境变量bootcmd和bootargs。
注:以上引用自“【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.1.pdf”
三、bootcmd和bootargs环境变量
uboot中有两个非常重要的环境变量bootcmd和bootargs,接下来看一下这两个环境变量。bootcmd和bootagrs是采用类似shell脚本语言编写的,里面有很多的变量引用,这些变量其实都是环境变量,有很多是NXP自己定义的。文件mx6ull_alientek_emmc.h中的宏CONFIG_EXTRA_ENV_SETTINGS保存着这些环境变量的默认值。宏CONFIG_EXTRA_ENV_SETTINGS是个条件编译语句,使用NAND和EMMC的时候宏CONFIG_EXTRA_ENV_SETTINGS的值是不同的。
1、环境变量bootcmd
bootcmd保存着uboot默认命令,uboot倒计时结束以后就会执行bootcmd中的命令。这些命令一般都是用来启动Linux内核的,比如读取EMMC或者NAND Flash中的Linux内核镜像文件和设备树文件到DRAM中,然后启动Linux内核。可以在uboot启动以后进入命令行设置bootcmd环境变量的值。如果EMMC或者NAND中没有保存bootcmd的值,那么uboot就会使用默认的值,板子第一次运行uboot的时候都会使用默认值来设置bootcmd环境变量。相关默认值在文件“include/env_default.h”。
文件中指定了很多环境变量的默认值,比如bootcmd的默认值就是CONFIG_BOOTCOMMAND,bootargs的默认值就是CONFIG_BOOTARGS。我们可以在mx6ull_onefu_emmc.h文件中通过设置宏CONFIG_BOOTCOMMAND来设置bootcmd的默认值。NXP官方设置的CONFIG_BOOTCOMMAND值如下:

#define CONFIG_BOOTCOMMAND \"run findfdt;" \"mmc dev ${mmcdev};" \"mmc dev ${mmcdev}; if mmc rescan; then " \"if run loadbootscript; then " \"run bootscript; " \"else " \"if run loadimage; then " \"run mmcboot; " \"else run netboot; " \"fi; " \"fi; " \"else run netboot; fi"
#endif

在这里插入图片描述

第205行,run findfdt;使用的是uboot的run命令来运行findfdt,findfdt是NXP自行添加的环境变量。findfdt是用来查找开发板对应的设备树文件(.dtb)。IMX6ULL EVK的设备树文件为imx6ull-14x14-evk.dtb,findfdt内容如下:

"findfdt="\ 
"if test $fdt_file = undefined; then " \ 
"if test $board_name = EVK && test $board_rev = 9X9; then " \  "setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \  "if test $board_name = EVK && test $board_rev = 14X14; then " \  "setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \ "if test $fdt_file = undefined; then " \  "echo WARNING: Could not determine dtb to use; fi; " \ "fi;\0" \ 

findfdt里面用到的变量有fdt_file,board_name,board_rev,这三个变量内容如下:

fdt_file=undefined,board_name=EVK,board_rev=14X14

findfdt做的事情就是判断,fdt_file是否为undefined,如果fdt_file为undefined的话那就要根据板子信息得出所需的.dtb文件名。此时fdt_file为undefined,所以根据board_name和board_rev来判断实际所需的.dtb文件,如果board_name为EVK并且board_rev=9x9的话fdt_file就为imx6ull-9x9-evk.dtb。如果board_name为EVK并且board_rev=14x14的话fdt_file就设置为imx6ull-14x14-evk.dtb。因此IMX6ULL EVK板子的设备树文件就是imx6ull-14x14-evk.dtb, 因此run findfdt的结果就是设置fdt_file为imx6ull-14x14-evk.dtb。
第206行,mmc dev ${mmcdev}用于切换mmc设备,mmcdev为1,因此这行代码就是:mmc dev 1,也就是切换到EMMC上。
第207行,先执行mmc dev ${mmcdev}切换到EMMC上,然后使用命令mmc rescan扫描看有没有SD卡或者EMMC存在,如果没有的话就直接跳到216行,执行run netboot,netboot也是一个自定义的环境变量,这个变量是从网络启动Linux的。如果mmc设备存在的话就从mmc设备启动。
第208行,运行loadbootscript环境变量,此环境变量内容如下:

loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script}; 

其中mmcdev=1,mmcpart=1,loadaddr=0x80800000,script= boot.scr,因此展开以后就是:

loadbootscript=fatload mmc 1:1 0x80800000 boot.scr; 

loadbootscript就是从mmc1的分区1中读取文件boot.src到DRAM的0X80800000处。但是mmc1的分区1中没有boot.src这个文件,可以使用命令“ls mmc 1:1”查看一下mmc1分区1中的所有文件,看看有没有boot.src这个文件。
第209行,如果加载boot.src文件成功的话就运行bootscript环境变量,bootscript的内容如下:

bootscript=echo Running bootscript from mmc ...; 
source

因为boot.src文件不存在,所以bootscript也就不会运行。
第211行,如果loadbootscript没有找到boot.src的话就运行环境变量loadimage,环境变量loadimage内容如下:

loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image} 

其中mmcdev=1,mmcpart=1,loadaddr=0x80800000,image = zImage,展开以后就是:

loadimage=fatload mmc 1:1 0x80800000 zImage 

可以看出loadimage就是从mmc1的分区中读取zImage到内存的0X80800000处,而mmc1的分区1中存在zImage。
第212行,加载linux镜像文件zImage成功以后就运行环境变量mmcboot,否则的话运行netboot环境变量。mmcboot环境变量如下:

"mmcboot=echo Booting from mmc ...; " \"run mmcargs; " \"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \"if run loadfdt; then " \"bootz ${loadaddr} - ${fdt_addr}; " \"else " \"if test ${boot_fdt} = try; then " \"bootz; " \"else " \"echo WARN: Cannot load the DT; " \"fi; " \"fi; " \"else " \"bootz; " \"fi;\0" \

在这里插入图片描述
第154行,输出信息“Booting from mmc …”。
第155行,运行环境变量mmcargs,mmcargs用来设置bootargs。
第156行,判断boot_fdt是否为yes或者try,根据uboot输出的环境变量信息可知boot_fdt=try。因此会执行157行的语句。
第157行,运行环境变量loadfdt,环境变量loadfdt定义如下:

loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}

展开以后就是:

loadfdt=fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb 

因此loadfdt的作用就是从mmc1的分区1中读取imx6ull-14x14-evk.dtb文件并放到0x83000000处。
第158行,如果读取.dtb文件成功的话那就调用命令bootz启动linux,调用方法如下:

bootz ${loadaddr} - ${fdt_addr}; 

展开就是:

bootz 0x80800000 - 0x83000000 (注意‘-’前后要有空格) 

至此Linux内核启动,如此复杂的设置就是为了从EMMC中读取zImage镜像文件和设备树文件。经过分析,浓缩出来的仅仅是4行精华:

mmc dev 1 //切换到EMMC 
fatload mmc 1:1 0x80800000 zImage //读取zImage到0x80800000处 
fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb //读取设备树到0x83000000处 
bootz 0x80800000 - 0x83000000 //启动Linux

NXP官方将CONFIG_BOOTCOMMAND写的这么复杂只有一个目的:为了兼容多个板子,所以写了个很复杂的脚本。当我们明确知道我们所使用的板子的时候就可以大幅简化宏CONFIG_BOOTCOMMAND的设置,比如我们要从EMMC启动,那么宏CONFIG_BOOTCOMMAND就可简化为:

#define CONFIG_BOOTCOMMAND \  "mmc dev 1;" \  "fatload mmc 1:1 0x80800000 zImage;" \  "fatload mmc 1:1 0x83000000 imx6ull-onefu-emmc.dtb;" \  "bootz 0x80800000 - 0x83000000;"

或者可以直接在uboot中设置bootcmd的值,这个值就是保存到EMMC中的,命令如下:

etenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-onefu-emmc.dtb; bootz 80800000 - 83000000;' 

2、环境变量bootargs
bootargs保存着uboot传递给Linux内核的参数,在上一小节讲解bootcmd的时候说过,bootargs环境变量是由mmcargs设置的,mmcargs环境变量如下:

mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot} 

其中console=ttymxc0,baudrate=115200,mmcroot=/dev/mmcblk1p2 rootwait rw,因此将mmcargs展开以后就是:

mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw

可以看出环境变量mmcargs就是设置bootargs的值为“console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw”,bootargs就是设置了很多的参数的值,这些参数Linux内核会使用到。
(1)console用来设置linux终端(或者叫控制台),也就是通过什么设备来和Linux进行交互,是串口还是LCD屏幕?如果是串口的话应该是串口几等等。一般设置串口作为Linux终端,这样我们就可以在电脑上通过SecureCRT来和linux交互了。这里设置console为ttymxc0,因为linux启动以后I.MX6ULL的串口1在linux下的设备文件就是/dev/ttymxc0,在Linux下,一切皆文件。
ttymxc0后面有个“,115200”,这是设置串口的波特率,console=ttymxc0,115200综合起来就是设置ttymxc0(也就是串口1)作为Linux的终端,并且串口波特率设置为115200。
(2)root用来设置根文件系统的位置,root=/dev/mmcblk1p2用于指明根文件系统存放在mmcblk1设备的分区2中。EMMC版本的核心板启动linux以后会存在/dev/mmcblk0、/dev/mmcblk1、/dev/mmcblk0p1、/dev/mmcblk0p2、/dev/mmcblk1p1和/dev/mmcblk1p2这样的文件,其中/dev/mmcblkx(x=0n)表示mmc设备,而/dev/mmcblkxpy(x=0n,y=1~n)表示mmc设备x的分区y。在I.MX6U-ALPHA开发板中/dev/mmcblk1表示EMMC,而/dev/mmcblk1p2表示EMMC的分区2。 root后面有“rootwait rw”,rootwait表示等待mmc设备初始化完成以后再挂载,否则的话mmc设备还没初始化完成就挂载根文件系统会出错的。rw表示根文件系统是可以读写的,不加rw的话可能无法在根文件系统中进行写操作,只能进行读操作。
(3)此选项一般配置root一起使用,rootfstype用于指定根文件系统类型,如果根文件系统为ext格式的话此选项无所谓。如果根文件系统是yaffs、jffs或ubifs的话就需要设置此选项,指定根文件系统的类型。 bootargs常设置的选项就这三个。

四、uboot启动Linux测试
测试两种启动Linux内核的方法,一种是直接从EMMC启动,一种是从网络启动。
1、从EMMC启动Linux系统
从EMMC启动也就是将编译出来的Linux镜像文件zImage和设备树文件保存在EMMC中,uboot从EMMC中读取这两个文件并启动,这个是我们产品最终的启动方式。但是目前还没有讲解如何移植linux和设备树文件,以及如何将zImage和设备树文件保存到EMMC中。不过作者拿到手的I.MX6U-ALPHA开发板(EMMC版本)已经将zImage文件和设备树文件烧写到了EMMC中,所以我们可以直接读取来测试(如果没有看下一小节,通过网络启动,等移植好linux和设备树,在测试也可)。先检查一下EMMC的分区1中有没有zImage文件和设备树文件,输入命令“ls mmc 1:1”,结果如下图所示:
在这里插入图片描述
从上图中可以看出,此时EMMC分区1中存在zimage和imx6ull-alientek-emmc.dtb这两个文件,所以我们可以测试新移植的uboot能不能启动linux内核。设置bootargs和bootcmd这两个环境变量,这里作者,借用正点原子已有的linux和设备树,后续,等讲解到linux和设备树的移植后,再测试一边。

以下是通过进入uboot后,再设置环境变量中的bootargs和bootcmd的方式,也可以在上一节的uboot源码中修改,并重新编译uboot。

进入uboot后,环境变量设置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;' 
saveenv

在这里插入图片描述
设置好以后直接输入boot,或者run bootcmd即可启动Linux内核,如果Linux内核启动成功的话就会输出如下图所示的启动信息:
在这里插入图片描述
2、从EMMC启动Linux系统
从网络启动linux系统的唯一目的就是为了调试!不管是为了调试linux系统还是linux下的驱动。每次修改linux系统文件或者linux下的某个驱动以后都要将其烧写到EMMC中去测试,这样太麻烦了。我们可以设置linux从网络启动,也就是将linux镜像文件和根文件系统都放到Ubuntu下某个指定的文件夹中,这样每次重新编译linux内核或者某个linux驱动以后只需要使用cp命令将其拷贝到这个指定的文件夹中即可,这样就不用需要频繁的烧写EMMC,这样就加快了开发速度。我们可以通过nfs或者tftp从Ubuntu中下载zImage和设备树文件,根文件系统的话也可以通过nfs挂载,不过本小节我们不讲解如何通过nfs挂载根文件系统,这个在讲解根文件系统移植的时候再讲解。这里我们使用tftp从Ubuntu中下载zImage和设备树文件,前提是要将zImage和设备树文件放到Ubuntu下的tftp目录中。
ubuntu中tftp相关使用可自行百度,或参考正点原子linux开发板教程,或参考tftp。

设置bootargs和bootcmd这两个环境变量,设置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' 
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000' 
saveenv 
boot

一开始是通过tftp下载zImage和imx6ull-alientek-emmc.dtb这两个文件,然后启动linux,过程如下图所示:
在这里插入图片描述
五、结语
uboot移植到此结束,简单总结一下uboot移植的过程:
①、不管是购买的开发板还是自己做的开发板,基本都是参考半导体厂商的dmeo板,而半导体厂商会在他们自己的开发板上移植好uboot、linux kernel和rootfs等,最终制作好BSP包提供给用户。我们可以在官方提供的BSP包的基础上添加我们的板子,也就是俗称的移植。
②、我们购买的开发板或者自己做的板子一般都不会原封不动的照抄半导体厂商的demo板,都会根据实际的情况来做修改,既然有修改就必然涉及到uboot下驱动的移植。
③、一般uboot中需要解决串口、NAND、EMMC或SD卡、网络和LCD驱动,因为uboot的主要目的就是启动Linux内核,所以不需要考虑太多的外设驱动。
④、在uboot中添加自己的板子信息,根据自己板子的实际情况来修改uboot中的驱动。

以上内容均参考正点原子linux开发板配套资料,如有不足,遗漏,错误之处,可联系作者,进一步改善。
如若获取更详细的资料可到正点原子官方网址下载。


http://chatgpt.dhexx.cn/article/5rRfMHfu.shtml

相关文章

X210开发板(S5PV210芯片)uboot移植DM9000驱动移植

前言 本文是介绍在uboot中如何移植DM9000的驱动&#xff0c;并不深入去讲解DM9000芯片的操作时序和内部寄存器&#xff0c;想要读懂驱动代码要仔细阅读DM9000芯片的数据手册。移植的基础是手里有DM9000芯片可以用的驱动代码&#xff0c;只需要根据开发板中DM9000芯片的接线方式…

嵌入式linux UBoot移植篇

如何在U-boot添加自己的linux板卡并启动呢&#xff1f; uboot 的移植并不是说我们完完全全的从零开始将 uboot 移植到我们现在所使用的开发板或者开发平台上。这个对于我们来说基本是不可能的&#xff0c;这个工作一般是半导体厂商做的&#xff0c; 半导体厂商负责将 uboot 移…

Uboot移植流程

linux-Bootloader&#xff08;Uboot&#xff09;移植流程 前言 最近在做ZigBee的温室大棚项目&#xff0c;将自己学习的过程和经验分享给大家。本文基于linux3.4.39内核版本&#xff0c;s5p6818开发板实现。 1、uboot启动简介 uboot启动的过程比较复杂&#xff0c;这里就只…

IMX6ULL Uboot 移植

使用的开发板&#xff1a;正点原子ALPHA V2.2 Uboot简介 在学习STM32的过程中使用过IAP在线升级就会知道&#xff0c;有引导程序APP程序&#xff0c;即bootloader程序APP。在学习嵌入式Linux的时候也一样&#xff0c;这个引导程序就是Uboot. uboot移植主要是根据原厂的uboot移…

二、uboot移植

二、uboot移植 版本作者时间备注V 1.0bug设计工程师2021/11/10创建文件软件网盘链接0交叉编译工具链接:https://pan.baidu.com/s/1yFO2NDMet9_b1E1q1rMwEA提取码:42kluboot源码同上linux源码同上文件系统工具同上tftp工具同上2.1 简单说明 uboot制作结束会生成 u-boot-etc44…

linux-uboot 移植四 uboot的移植

概述 前边的章节中介绍到如果要移植uboot的话&#xff0c;最好的参考就是由官方提供的demo。 1、移植 1.1 添加board对应的板级文件夹 uboot 中每个板子都有一个对应的文件夹来存放板级文件&#xff0c;比如开发板上外设驱动文件等等。 NXP 的 I.MX 系列芯片的所有板级文件…

[uboot 移植]uboot 移植过程

文章目录 uboot 移植1 修改顶层 Makefile2 在 board 文件夹下添加开发板对应的板级文件2.1 imximage_lpddr2.cfg 和 imximage.cfg 文件2.2 plugin.S 文件2.3 Kconfig 文件2.4 igkboard.c 文件2.5 MAINTAINERS 文件2.6 Makefile 文件 3 添加 igkboard_defconfig 配置文件4 添加开…

UBoot 移植

1 NXP官方开发板uboot编译测试 1 查找 NXP 官方的开发板默认配置文件 因为我们的开发板是参考 NXP 官方的 I.MX6ULL EVK 开发板做的硬件&#xff0c;因此我们在移植 uboot 的时候就可以以 NXP 官方的 I.MX6ULL EVK 开发板为蓝本。 在 NXP 官方 I.MX6UL/6ULL 默认配置文件中找…

大话uboot 移植

结合作者多年的移植经验&#xff0c;尽量简单的为大家描述一个uboot 的移植过程。希望通过描述&#xff0c;给初入移植行道的你带来美好的希望。接下来&#xff0c;我们通过以下几个方面来描述。 1. arm soc 的启动方式 在描述soc 前&#xff0c;我们先看下一个简单的arm soc:…

uboot移植步骤

Uboot移植具体步骤(本例子为Samsung origen板) 第一步:准备源码 网上下载现成的uboot开源代码:https://ftp.denx.de/pub/u-boot/ 在该网站中选择与板子兼容的uboot源文件(公司中一般咨询硬件工程师) 在Linux系统下解压 tar xf 压缩包名 第二步:修改源码 1.抄板:将和你板子兼容…

(二)uboot移植--从零开始自制linux掌上电脑(F1C200S)<嵌入式项目>

目录 一、前言 二、F1C200s上电启动顺序 三、前期准备 四、新建用户 五、交叉编译环境配置 六、uboot简介 七、uboot移植 &#x1f34f; uboot下载 &#x1f34f; uboot默认配置 &#x1f34f; uboot图形界面配置 &#x1f34f; uboot编译 &#x1f34f; 烧录bin…

U-Boot 移植初探

1. NXP官方开发板uboot编译测试 uboot移植不需要从零开始将uboot移植到使用的开发板上。因为半导体厂商通常都会自己做一个开发板&#xff0c; 将uboot移植到他们自己的原厂开发板上&#xff0c;再将这个uboot&#xff08;原厂BSP 包&#xff09;发布出去。因此使用自已的开发…

U-Boot移植

一、U-Boot Linux 系统要启动就必须需要一个 bootloader 程序&#xff0c;芯片上电以后先运行一段bootloader程序。 bootloader程序会先初始化DDR等外设&#xff0c;然后将Linux内核从flash(NAND&#xff0c;NOR FLASH&#xff0c; SD&#xff0c; eMMC 等)拷贝到 DDR 中&…

uboot移植

一、我们知道uboot就是一个Bootloader。但是&#xff0c;arm不像我们的pc机一样&#xff0c;用一个老毛桃随便找一个网站下一个windows镜像就可以直接装了。 我们的uboot对应的就是老毛桃里面刷的引导程序。 虽然uboo支持很多架构很多不同的厂家的板子&#xff0c;但是UBOOT它…

【Linux】系统移植篇四--uboot移植

系统移植篇四--uboot移植 一、uboot源码结构1、uboot源码获取2、uboot特点3、uboot源码结构 二、uboot的配置与编译1、uboot配置2、uboot编译 前言&#xff1a;本篇主要介绍uboot的一些结构与相关配置&#xff0c;uboot是一款免费开源的芯片启动软件&#xff0c;代码完全开源&a…

uboot移植过程

uboot移植过程 IMX6ULL 文章目录 uboot移植过程 IMX6ULL 前言一、从原厂中移植uboot进行测试二、在U-Boot中添加自己的硬件1. 添加默认配置文件2. 添加对应的头文件3. 添加对应的板级文件夹3.1 修改Makefile文件3.2 修改 mx6ull_alientek 目录下的 imximage.cfg 文件3.3 修改 m…

MediaCodec对接到OMX的简单分析

一、引言&#xff1a; nuplayer播放器是使用MediaCodec来进行编解码的&#xff0c;而OMX组件则是MediaCodec的解码核心&#xff0c;但是因为涉及的面太过底层&#xff0c;往往是芯片公司才会涉及到这一块&#xff0c;所以就做一个简单分析&#xff0c;对通路有个大致了解就行。…

MediaCodec(native)状态机分析

一、引入&#xff1a; MediaCodec这条通路的调用逻辑是MediaCode->ACodec->OMX&#xff0c;因为OMX有自己的状态机&#xff0c;所以MediaCodec和ACodec也分别基于OMX组件的调用维护了其状态机&#xff0c;这篇博客就先分析MediaCodec的状态机是如何运转的。 二、MediaCo…

视频-MediaCodec

1.解析视频可以使用android 提供的api MediaPlayer,实现简单的播放暂停&#xff0c;提取视频中的一帧或者编辑视频&#xff0c;需要另一个api MediaCodec&#xff08;硬解&#xff0c;控制DSP芯片&#xff09;或者 ffmpeg(软解&#xff0c;耗时)&#xff0c;选择的优先级一定要…

MediaCodec解析MP4视频

MediaCodec讲解 MediaCodec是Android提供的用于对音视频进行编解码的类&#xff0c;它通过访问底层的codec来实现编解码的功能。是Android media基础框架的一部分&#xff0c;通常和 MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface和AudioTra…