uboot实际上就是一个裸机程序,但它是用来引导linux内核启动的,就像电脑上的bios。
本文只要是记录利用NXP官方的uboot进行改造,适配正点原子IMX6ULL阿尔法开发板的过程
(可能不全)
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/configs/mx6ull_14x14_evk_defconfig
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include/configsmx6ullevk.h
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/board/freescale/mx6ullevk/Makefile
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/board/freescale/mx6ullevk/imximage.cfg
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/board/freescale/mx6ullevk/Kconfig
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/board/freescale/mx6ullevk/MAINTAINERS
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/cpu/armv7/mx6/Kconfig
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/mx6ull_14x14_evk_emmc.sh
/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/drivers/net/phy/phy.c
如上述所示,是需要与自己开发板进行适配调整的文件路径及文件名。如果原厂u-boot只是对NXP官方开发板进行适配,当我们用自己的开发板时还需要进行修改,比如显示屏、网络等。
下图是NXP官方uboot解压后的文件目录概览
每个文件/文件夹的介绍,加粗的是最重要的部分
名称 | 介绍 |
---|---|
api | 一些与硬件无关的API函数 |
arch | 与架构体系有关的内容 |
board | 板级支持包,用来适配不同开发板 |
cmd | 命令相关的代码 |
common | 通用代码 |
config.mk | 被某个Makefile调用 |
configs | 配置文件 |
disk | 磁盘分区相关代码 |
doc | 文档 |
drivers | 驱动代码 |
dts | 设备树 |
examples | 例程 |
fs | 文件系统 |
imxdownload | SD卡烧写软件(来自正点原子) |
include | 头文件 |
kbuild | 用于生成和汇编有关的文件 |
kconfig | 图形化配置界面描述文件 |
lib | 库文件 |
Licenses | 许可证 |
load.imx | 烧写SD卡后产生的文件 |
MAINTAINERS | 维护者联系方式文件 |
MAKEALL | shell脚本,辅助编译uboot |
Makefile | 主要的Makefile文件 |
mx6ull_14x14_evk_emmc.sh | 编译原厂开发板的uboot脚本 |
mx6ull_alientek_emmc.sh | 编译自己的开发板的uboot脚本 |
net | 网络相关代码 |
post | 上电自检程序 |
README | 说明 |
scripts | 脚本文件 |
snapshot.commit | 快照提交(不知道是啥) |
system.map | 系统映射文件 |
test | 测试代码 |
tools | 工具 |
u-boot | 编译得到的uboot文件 |
u-boot.xx | 与uboot相关的文件,u-boot.bin文件是要烧写的文件 |
添加默认配置文件:进入configs文件夹中,该文件夹保存了各种开发板的默认配置文件。找到mx6ull_14x14_evk_emmc_defconfig这个文件。将其拷贝一份并重命名为mx6ull_alientek_emmc_defconfig(这里命名我是跟着原子来的,也可以自己设置个名字,注意配置过程中别输错名字就行。)
要修改的内容:主要修改文件中以下的两个红框内的内容
一个是修改 .imx文件的生成工具imximage.sh的路径。
添加对应的头文件:
开发板的头文件位于**/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include/configs目录下,找到mx6ullevk.h文件,复制一份重命名为mx6ull_alientek_emmc.h**,打开并修改一个宏定义
将红框内的代码修改成如下代码:
#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H
#define __MX6ULL_ALIENTEK_EMMC_CONFIG_H
添加并修改板级文件夹:
uboot关于开发板的板级文件夹位于**/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/board这个目录下,而NXP 的 I.MX 系列芯片的所有板级文件夹都存放在 该目录的freescale**文件夹下,在这个目录下有个名为 mx6ullevk 的文件夹,这个文件夹就是 NXP 官方 I.MX6ULL EVK 开发板的板级文件夹。
找到mx6ullevk 文件夹复制一份并重命名为mx6ull_alientek_emmc
cd board/freescale/
cp mx6ullevk/ -r mx6ull_alientek_emmc
文件夹的内容如下:
将其中的mx6ullevk.c文件重命名为mx6ull_alientek_emmc.c
然后开始修改文件内容
obj-y := mx6ull_alientek_emmc.o
PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000
修改为:
if TARGET_MX6ULL_ALIENTEK_EMMC
config SYS_BOARD
default "mx6ull_alientek_emmc"
config SYS_VENDOR
default "freescale"
config SYS_SOC
default "mx6"
config SYS_CONFIG_NAME
default "mx6ull_alientek_emmc"
endif
MX6ULL_ALIENTEK_EMMC BOARD
M: Peng Fan
S: Maintained
F: board/freescale/mx6ull_alientek_emmc/
F: include/configs/mx6ull_alientek_emmc.h
修改uboot图形界面配置文件
文件路径:/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/cpu/armv7/mx6
主要修改Kconfig文件。打开文件,在207行的位置,添加如下内容
config TARGET_MX6ULL_ALIENTEK_EMMC
bool "Support mx6ull_alientek_emmc"
select MX6ULL
select DM
select DM_THERMAL
source "board/freescale/mx6ull_alientek_emmc/Kconfig"
添加后如图示:
经过这四步,阿尔法开发板就添加进了uboot里了,接下来就是编译uboot
在**/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek**下编写shell脚本。
脚本命名为mx6ull_alientek_emmc.sh,以下是脚本代码。但是要注意一点:执行distclean即清理时会将uboot图像化配置中的配置参数清除。
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
然后给脚本分配权限
chmod 777 mx6ull_alientek_emmc.sh
最后是运行脚本编译uboot
./mx6ull_alientek_emmc.sh
这个命令可以查看头文件是否被引用。
grep -nR "mx6ull_alientek_emmc.h"
这时的uboot中的各种驱动还是默认配置,与开发板的外设还有些不匹配,主要是显示屏和网络接口参数,接下来就要修改这些驱动配置。
打开文件:mx6ull_alientek_emmc.c
位于:/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/board/freescale/mx6ull_alientek_emmc
找到如下代码,按照自己用的显示屏修改参数,我这里用的是7寸800*480的屏幕,名字命名为TFT7084。
(其中pixclock = (1/屏幕要求的像素时钟)*10^12)
(不同种屏幕的各种参数可以在正点原子讲解RGB LCD的代码中找到,也可以参考各数据手册。)
打开文件:mx6ull_alientek_emmc.h
位于:/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include/configs
将所有panel的值改为TFT7084,要和mx6ull_alientek_emmc.c文件中的name一致
这样显示屏的相关参数就修改完了,接下来修改网络方面的代码
先打开文件mx6ull_alientek_emmc.h文件
①、 ENET1 网络 PHY 的地址。
②、 ENET2 网络 PHY 的地址。
③、 使能 PHY 驱动(要改为SMSC公司的PHY驱动)。
修改后的代码:
再打开文件mx6ull_alientek_emmc.c文件
#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)
让ENET1 的复位引脚连接到 SNVS_TAMPER7 上,对应 GPIO5_IO07,ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO08
找到函数static void iox74lv_init**(void)** 和void iox74lv_set**(int index)** 并删除。
再找到开发板初始化函数board_init(void)
删除如下代码:
imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));
iox74lv_init();
继续添加 I.MX6U-ALPHA 开发板网络复位引脚驱动,找到
static iomux_v3_cfg_t const fec1_pads[] 和 static iomux_v3_cfg_t const fec2_pads[] ,位于640行和653行
在static iomux_v3_cfg_t const fec1_pads[]中添加:
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
在static iomux_v3_cfg_t const fec2_pads[]中添加:
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
继续找到函数setup_iomux_fec(函数位于668行)进行修改,添加网络复位IO的初始化代码,修改后如下:
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);
}
}
最后找到phy.c文件进行修改
文件位置:/home/swiler/uboot_official/uboot-imx-rel_imx_4.1.15_2.1.0_ga_alientek/drivers/net/phy
打开phy.c文件找到 genphy_update_link(struct phy_device *****phydev) ,这是个通用 PHY 驱动函数,此函数用于更新 PHY 的连接状态和速度,使用 LAN8720A 的时候需要在此函数中添加一些代码。修改后的函数如下:(主要是#ifdef到#endif之间的内容)
int genphy_update_link(struct phy_device *phydev)
{
unsigned int mii_reg;
#ifdef CONFIG_PHY_SMSC
static 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);
..................
return 0;
}
重新编译uboot,利用imxdownload工具将u-boot.bin烧入到SD卡中,把SD卡插入开发板,启动方式调节为SD卡启动,开发板连接网线和串口USB,上电复位。
在autoboot这里倒计时结束之前按任意键就可以进入uboot
接下来配置网络相关的环境变量
setenv ipaddr 192.168.1.55 //开发板 IP 地址
setenv ethaddr b8:ae:1d:01:00:00 //开发板网卡 MAC 地址
setenv gatewayip 192.168.1.1 //开发板默认网关
setenv netmask 255.255.255.0 //开发板子网掩码
setenv serverip 192.168.1.250 //服务器地址,也就是 Ubuntu 地址
saveenv //保存环境变量
然后ping下主机,即Ubuntu的IP,如果ping通了,就如下图所示。
先配置 bootargs 和 bootcmd这两个环境变量
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 内核。
如果内核启动成功就能进入系统了。
先配置 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
下载好zImage和imx6ull-alientek-emmc.dtb后,效果和从EMMC启动linux系统类似。
以上就完成了利用原厂的u-boot来构建符合自身开发板的u-boot的移植了。