U-Boot移植
下载NXP官方维护的uboot-imx-rel_imx_4.1.15_2.1.0_ga版本
git clone -b rel_imx_4.1.15_2.1.0_ga --single-branch git://source.codeaurora.org/external/imx/uboot-imx.git
如果下载速度过慢,也可以从以下国内的gitee仓库下载
git clone https://gitee.com/SudekiMing/uboot-imx-rel_imx_4.1.15_2.1.0_ga.git
在移植之前,我们需要先编译一下 NXP 官方 I.MX6ULL EVK 开发板对应的 uboot,首先是配置uboot, configs 目录下有很多跟 I.MX6UL/6ULL 有关的配置如图:
其中以 mx6ul 开头的是 I.MX6UL 芯片的,mx6ull 开头的是 I.MX6ULL 开发板的。 I.MX6UL/6ULL 有 9x9mm 和 14x14mm 两种尺寸的,所以我们可以看到会有mx6ull_9x9和mx6ull_14x14开头的默认配置文件。我们使用的是14x14mm的芯片,所以关注 mx6ull_14x14 开头的默认配置文件。
我的开发板是EMMC版本,因此我只 需 要 关 注 mx6ull_14x14_evk_emmc_defconfig ,使用 mx6ull_14x14_evk_emmc_defconfig 作为默认配置文件。
1.1 编译 NXP 官方开发板对应的 uboot
找到 NXP 官方 I.MX6ULL EVK 开发板对应的默认配置文件以后就可以编译一下,使用如下命令编译 uboot:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
编译完成以后结果如图
我们在编译的时候需要输入 ARCH 和 CORSS_COMPILE这两个变量的值,这样太麻烦了。我们可以直接在顶层 Makefile 中直接给 ARCH 和CORSS_COMPILE 赋值,修改如图
这样我们就可以使用如下简短的命令来编译 uboot 了:
make mx6ull_14x14_evk_emmc_defconfig
make V=1 -j4
编译完成以后会生成 u-boot.bin、 u-boot.imx 等文件,但是这些文件是 适配的NXP 官方 I.MX6ULLEVK 开发板。
1.2 在 U-Boot 中添加自己的开发板
1.2.1 添加开发板默认配置文件
先在 configs 目录下创建默认配置文件,复制 mx6ull_14x14_evk_emmc_defconfig,然后重命名为 mx6ull_alientek_emmc_defconfig,命令如下:
cd configs
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_14x14_atk_emmc_defconfig
然后将文件 mx6ull_14x14_atk_emmc_defconfig 中的内容改成下面的(只是第 1 行和第 4 行做了修改 ):
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_14x14_atk_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_14X14_ATK_EMMC=y
CONFIG_CMD_GPIO=y
1.2.2 添加开发板对应的头文件
在 目 录 include/configs 下 添 加 I.MX6ULL-ALPHA 开 发 板 对 应 的 头 文 件 , 复 制include/configs/mx6ullevk.h,并重命名为 mx6ullatk.h,命令如下:
cp include/configs/mx6ullevk.h include/configs/mx6ullatk.h
拷贝完成以后将:
#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H
改为:
#ifndef __MX6ULLATK_CONFIG_H
#define __MX6ULLATK_CONFIG_H
mx6ullatk.h里面有很多宏定义,这些宏定义基本用于配置 uboot,也有一些I.MX6ULL 的配置项目。 文件中基本都是“CONFIG_”开头
的宏定义,这也说明 mx6ullatk.h 文件的主要功能就是配置或者裁剪 uboot。如果需要某个功能的话就在里面添加这个功能对应的 CONFIG_XXX 宏即可,如果不需要某个功能的话就删除掉对应的宏即可。
1.2.3 添加开发板对应的板级文件夹
uboot 中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等等。 NXP 的 I.MX 系列芯片的所有板级文件夹都存放在 board/freescale 目录下,在这个目录下有个名为 mx6ullevk 的文件夹,这个文件夹就是 NXP 官方 I.MX6ULL EVK 开发板的板级文件夹。复制 mx6ullevk,将其重命名为 mx6ullatk,命令如下:
cd board/freescale/
cp mx6ullevk/ -r mx6ullatk
进 入 mx6ullatk 目 录 中 , 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为mx6ullatk.c,命令如下:
cd mx6ullatk
mv mx6ullevk.c mx6ullatk.c
我们还需要对 mx6ullatk 目录下的文件做一些修改:
1、修改 mx6ull_alientek_emmc 目录下的 Makefile 文件
# (C) Copyright 2015 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y := mx6ullatk.o
extra-$(CONFIG_USE_PLUGIN) := plugin.bin
$(obj)/plugin.bin: $(obj)/plugin.o
$(OBJCOPY) -O binary --gap-fill 0xff $< $@
重点是第 6 行的 obj-y,改为 mx6ullatk.o,这样才会编译 mx6ullatk.c这个文件
2、修改 mx6ullatk目录下的 imximage.cfg 文件
将 imximage.cfg 中的下面一句:
PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
改为:
PLUGIN board/freescale/mx6ullatk/plugin.bin 0x00907000
3、修改 mx6ullatk目录下的 Kconfig 文件
修改 Kconfig 文件,修改后的内容如下:
if TARGET_MX6ULL_14X14_ATK_EMMC
config SYS_BOARD
default "mx6ullatk"
config SYS_VENDOR
default "freescale"
config SYS_SOC
default "mx6"
config SYS_CONFIG_NAME
default "mx6ullatk"
endif
4、修改 mx6ullatk目录下的 MAINTAINERS 文件
修改 MAINTAINERS 文件,修改后的内容如下:
MX6ULLATK BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ullatk/
F: include/configs/mx6ullatk.h
F: configs/mx6ull_14x14_atk_defconfig
1.3 修改 U-Boot 图形界面配置文件
uboot 是支持图形界面配置的,修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),在 207 行前加入如下内容:
config TARGET_MX6ULL_14X14_ATK_EMMC
bool "Support mx6ull_14x14_atk_emmc"
select MX6ULL
select DM
select DM_THERMAL
在最后一行的 endif 的前一行添加如下内容:
source "board/freescale/mx6ullatk/Kconfig"
添加完成以后的 Kconfig 文件的改动如下:
到此为止, I.MX6U-ALPHA 开发板就已经添加到 uboot 中了,接下来就是编译这个新添加的开发板。
1.4 使用新添加的板子配置编译 uboot
# 清理工程
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
# 配置 uboot
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_atk_emmc_defconfig
# 编译
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
# 在顶层Makefile中配置修改过ARCH和CORSS_COMPILE,可直接使用下面简化的指令编译
# 清理工程
make distclean
# 配置 uboot
make mx6ull_14x14_atk_emmc_defconfig
# 编译
make -j4
等 待 编 译 完 成 , 编 译 完成 以 后 输 入 如 下命 令, 查 看 一 下 添加 的mx6ullatk.h 这个头文件有没有被引用。如果有很多文件都引用了mx6ull_alientek_emmc.h这个头文件,那就说明新板子添加成功。
grep -nR "mx6ullatk.h"
1.5 LCD 驱动修改
如果你用的不是正点原子的 4.3 寸 480x272 分辨率的屏幕的话,那么 LCD 就不会显示 以上logo 界面。因为 NXP 官方 I.MX6ULL 开发板的屏幕就是 4.3 寸 480x272 分辨率的,所以 uboot 默认 LCD 驱动是 4.3 寸 480x272 分辨率的。如果使用其他分辨率的 LCD 就需要修改 LCD 驱动。(因为我本次试验用就是正点原子 4.3 寸 480x272 分辨率的屏幕,故NXP logo正常显示,驱动不用做修改)
1.6 网络驱动修改
注意!正点原子I.MX6U-ALPHA开发板V2.4版本以前的底板使用的网络PHY为LAN8720,V2.4 及其以后的版本使用的网络 PHY 为 SR8201F,而且网络 PHY 地址有改变,大家一定要看准自己所使用的底板版本号!(我的底板版本为V1.7)
1.6.1 I.MX6U-ALPHA 开发板网络简介
I.MX6UL/ULL 内部有个以太网 MAC 外设,也就是 ENET,需要外接一个 PHY 芯片来实现网络通信功能,也就是内部 MAC+外部 PHY 芯片的方案。
I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2,正点原子的 I.MX6U-ALPHA 开发板提供了这两个网络接口,其中 ENET1 和 ENET2 都使用 LAN8720A 作为 PHY 芯片(注:正点原子Mini LinuxI.MX6ULL只有一个网络接口ENET2,我这里使用的是Mini LinuxI.MX6ULL开发板)。
NXP 官方的I.MX6ULL EVK 开发板使用 KSZ8081 这颗 PHY 芯片, LAN8720A 相比 KSZ8081 具有体积小、外围器件少、价格便宜等优点。直接使用 KSZ8081 固然可以,但是我们在实际的产品中不一定会使用 KSZ8081,有时候为了降低成本会选择其他的 PHY 芯片。
1.6.2 网络 PHY 地址修改
首先修改 uboot 中的 ENET1 和 ENET2 的 PHY 地址和驱动,打开 mx6ullatk.h这个文件,找到如下代码:
第 331 行的宏 CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择ENET2(建议大家将ENET2 设置为 uboot 的默认网卡!也就是将宏 CONFIG_FEC_ENET_DEV 设置为 1)。
第 335 行为 ENET1 的 PHY 地址,默认是 0X2,第 339 行为 ENET2 的 PHY 地址,默认为 0x1。根据前面的分析可知,正点原子的 I.MX6U-ALPHA 开发板 ENET1 的 PHY 地址为0X0, ENET2 的 PHY 地址为 0X1,所以需要将第 335 行的宏 CONFIG_FEC_MXC_PHYADDR改为 0x0。第 345 行定了一个宏 CONFIG_PHY_MICREL,此宏用于使能 uboot 中 Micrel 公司的 PHY驱动, KSZ8081 这颗 PHY 芯片就是 Micrel 公司生产的,不过 Micrel 已经被 Microchip 收购了。
如果要使用 LAN8720A,那么就得将 CONFIG_PHY_MICREL 改为 CONFIG_PHY_SMSC,也就是使能 uboot 中的 SMSC 公司中的 PHY 驱动,因为 LAN8720A 就是 SMSC 公司生产的。
所以示例代码有三处要修改:
①、修改 ENET1 网络 PHY 的地址。
②、修改 ENET2 网络 PHY 的地址。
③、使能 SMSC 公司的 PHY 驱动。
1.6.3 删除 uboot 中 74LV595 的驱动代码
uboot 中网络 PHY 芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开mx6ullatk.c,找到如下代码:
示例代码中以 IOX 开头的宏定义是 74LV595 的相关 GPIO,因为 NXP 官方I.MX6ULL EVK 开发板使用 74LV595 来扩展 IO,两个网络的复位引脚就是由 74LV595 来控制的。正点原子的 I.MX6U-ALPHA 开发板并没有使用 74LV595,因此我们将示例代码中的代码删除掉,
ENET1 的复位引脚连接到 SNVS_TAMPER7 上,对应 GPIO5_IO07, ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO08。
继续在 mx6ullatk.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),
};
同理,示例代码是 74LV595 的 IO 配置参数结构体,将其删除掉。
继续在mx6ullatk.c 中找到函数 iox74lv_init,iox74lv_init 函数是 74LV595 的初始化函数, iox74lv_set 函数用于控制 74LV595 的 IO 输出电平,将这两个函数全部删除掉!
在 mx6ullatk.c 中找到 board_init 函数,此函数是板子初始化函数,会被board_init_r 调用
board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化74lv595 的 GPIO,将这两行删除掉。
至此, mx6ullatk.c 中关于 74LV595 芯片的驱动代码都删除掉了,接下来就是添加 I.MX6U-ALPHA 开发板两个网络复位引脚了。
1.6.4 添加 I.MX6U-ALPHA 开发板网络复位引脚驱动
在 mx6ullatk.c 中找到如下所示代码:
结构体数组 fec1_pads 和 fec2_pads 是 ENET1 和 ENET2 这两个网口的 IO 配置参数,在这两个数组中添加两个网口的复位 IO 配置参数,完成以后如下所示:
示例代码中,第 651 行和 667 行分别是 ENET1 和 ENET2 的复位 IO 配置参数。继续在文件 mx6ullatk.c 中找到函数 setup_iomux_fec,
函数 setup_iomux_fec 就是根据 fec1_pads 和 fec2_pads 这两个网络 IO 配置数组来初始化I.MX6ULL 的网络 IO。我们需要在其中添加网络复位 IO 的初始化代码,并且复位一下 PHY 芯片,修改后的 setup_iomux_fec 函数如下:
示例代码中第 676 行~679 行和第 685 行~688 行分别对应 ENET1 和 ENET2 的复位 IO 初始化,将这两个 IO 设置为输出并且硬件复位一下 LAN8720A,这个硬件复位很重要!否则可能导致 uboot 无法识别 LAN8720A。
1.6.5 修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link
大功基本上告成,还差最后一步, uboot 中的 LAN8720A 驱动有点问题,打开文件drivers/net/phy/phy.c,找到函数 genphy_update_link,这是个通用 PHY 驱动函数,此函数用于更新 PHY 的连接状态和速度。使用 LAN8720A 的时候需要在此函数中添加一些代码,修改后的函数 genphy_update_link 如下所示:
225 行~237 行就是新添加的代码,为条件编译代码段,只有使用 SMSC 公司的 PHY 这段代码才会执行(目前只测试了 LAN8720A, SMSC 公司其他的芯片还未测试)。第 229 行读取LAN8720A 的 BMCR 寄存器(寄存器地址为 0),此寄存器为 LAN8720A 的配置寄存器,这里先读取此寄存器的默认值并保存起来。 230 行向寄存器 BMCR 寄存器写入 BMCR_RESET(值为0X8000),因为 BMCR 的 bit15 是软件复位控制位,因此 230 行就是软件复位 LAN8720A,复位完成以后此位会自动清零。第 231~233 行等待 LAN8720A 软件复位完成,也就是判断 BMCR的 bit15 位是否为 1,为 1 的话表示还没有复位完成。第 234 行重新向 BMCR 寄存器写入以前的值,也就是 229 行读出的那个值。至此网络的复位引脚驱动修改完成,重新编译 uboot,然后将 u-boot.bin 烧写到 SD 卡中并启动。
1.7 修改uboot 启动信息 Board名字
在 uboot 启动信息中会有“Board: MX6ULL 14x14 EVK”这一句,也就是说板子名字为“ MX6ULL 14x14 EVK”,要将其改为我们所使用的板子名字,比如“ MX6ULL 14x14 ATK” 。打开文件 mx6ullatk.c,找到函数checkboard,将其做如下修改:
修改完成以后重新编译 uboot 并烧写到 SD 卡中验证, uboot 启动信息如图
可以看出, Board 变成了“MX6ULL ALIENTEK EMMC”。至此 uboot 的驱动部分就修改完成了, uboot 移植也完成了。
总结:一般 uboot 中需要解决串口、 NAND、 EMMC 或 SD 卡、网络和 LCD 驱动,因为 uboot的主要目的就是启动 Linux 内核,所以不需要考虑太多的外设驱动。