一、开发环境
- 嵌入式 Linux 开发板:100ASK-6ULL-V11(即:由百问网出品的 i.MX6ULL-PRO);
- 系统:Ubuntu 18.04(已配置交叉编译工具链);
- 待移植的 U-Boot:由 NXP 官方维护的 imx_v2020.04_5.4.47_2.2.0。
二、下载待移植的 U-Boot 源码
可以使用以下命令:
git clone https://github.com/nxp-imx/uboot-imx
cd uboot-imx
git branch -a
git checkout remotes/origin/imx_v2020.04_5.4.47_2.2.0
NXP 官方的项目集合了多个版本的 U-Boot,项目较大,如果多次克隆失败的话,也可以通过韦东山老师的仓库来克隆:
git clone https://gitee.com/weidongshan/uboot-imx
cd uboot-imx
git reset d95408316b25d766d65397df42419b88fda3bbe1 --hard
三、移植 U-Boot
可以尝试使用默认配置来编译,我们这里就不尝试了哈,已知问题有:网卡不能正常驱动、LCD 屏幕参数不适配等等(其实尝试过,但没有截图🤣),我们直接开始移植。
1. 建立单板相关配置
建立单板的配置文件和头文件:
cp configs/mx6ull_14x14_evk_emmc_defconfig configs/mx6ull_14x14_angus_emmc_defconfig
cp include/configs/mx6ullevk.h include/configs/mx6ullangus.h
修改配置文件mx6ull_14x14_angus_emmc_defconfig
的对应项为:
CONFIG_TARGET_MX6ULL_14X14_ANGUS=y
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ullangus/imximage.cfg"
CONFIG_DEFAULT_DEVICE_TREE="imx6ull-14x14-angus-emmc"
修改头文件mx6ullangus.h
的对应项为:
#ifndef __MX6ULLANGUS_CONFIG_H
#define __MX6ULLANGUS_CONFIG_H
同时修改该文件中查找设备树的命令:
添加 board 文件夹:
cp board/freescale/mx6ullevk board/freescale/mx6ullangus -r
进入该文件夹后,修改文件名:
mv mx6ullevk.c mx6ullangus.c
同时修改其对应内容:
#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
env_set("board_name", "ANGUS");
if (is_mx6ull_9x9_evk())
env_set("board_rev", "9X9");
else
env_set("board_rev", "14X14");
if (is_cpu_type(MXC_CPU_MX6ULZ)) {
env_set("board_name", "ULZ-EVK");
env_set("usb_net_cmd", "usb start");
}
#endif
int checkboard(void)
{
if (is_mx6ull_9x9_evk())
puts("Board: MX6ULL 9x9 EVK\n");
else if (is_cpu_type(MXC_CPU_MX6ULZ))
puts("Board: MX6ULZ 14x14 EVK\n");
else
puts("Board: MX6ULL 14x14 ANGUS\n");
return 0;
}
修改文件imximage.cfg
的对应项为:
#ifdef CONFIG_USE_IMXIMG_PLUGIN
/*PLUGIN plugin-binary-file IRAM_FREE_START_ADDR*/
PLUGIN board/freescale/mx6ullangus/plugin.bin 0x00907000
#else
修改文件Kconfig
为:
if TARGET_MX6ULL_14X14_ANGUS || TARGET_MX6ULL_9X9_EVK
config SYS_BOARD
default "mx6ullangus"
config SYS_VENDOR
default "freescale"
config SYS_CONFIG_NAME
default "mx6ullangus"
config SYS_TEXT_BASE
default 0x87800000
endif
修改文件MAINTAINERS
为:
MX6ULLANGUS BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ullangus/
F: include/configs/mx6ullangus.h
F: configs/mx6ull_14x14_angus_defconfig
F: configs/mx6ull_14x14_angus_plugin_defconfig
F: configs/mx6ulz_14x14_angus_defconfig
修改文件Makefile
的对应项为:
obj-y := mx6ullangus.o
增加设备树文件:
cp arch/arm/dts/imx6ull-14x14-evk-emmc.dts arch/arm/dts/imx6ull-14x14-angus-emmc.dts
cp arch/arm/dts/imx6ull-14x14-evk.dts arch/arm/dts/imx6ull-14x14-angus.dts
cp arch/arm/dts/imx6ul-14x14-evk.dtsi arch/arm/dts/imx6ul-14x14-angus.dtsi
cp arch/arm/dts/imx6ul-14x14-evk-u-boot.dtsi arch/arm/dts/imx6ul-14x14-angus-u-boot.dtsi
修改文件imx6ull-14x14-angus-emmc.dts
的对应项为:
#include "imx6ull-14x14-angus.dts"
修改imx6ull-14x14-angus.dts
为
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
//
// Copyright (C) 2016 Freescale Semiconductor, Inc.
/dts-v1/;
#include "imx6ull.dtsi"
#include "imx6ul-14x14-angus.dtsi"
#include "imx6ul-14x14-angus-u-boot.dtsi"
/ {
model = "i.MX6 ULL 14x14 ANGUS Board";
compatible = "fsl,imx6ull-14x14-angus", "fsl,imx6ull";
};
&clks {
assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>;
assigned-clock-rates = <320000000>;
};
在编译设备树的文件arch/arm/dts/Makefile
中添加我们的板子:
在文件arch/arm/mach-imx/mx6/Kconfig
添加我们的板子,以支持 U-Boot 的图形化配置:
config TARGET_MX6ULL_14X14_ANGUS
bool "Support mx6ull_14x14_angus"
select BOARD_LATE_INIT
select DM
select DM_THERMAL
select MX6ULL
imply CMD_DM
source "board/freescale/mx6ullangus/Kconfig"
2. 适配网卡驱动和 LCD 屏幕参数
适配 LAN8720A 网卡
为了支持 U-Boot 从网络启动 Linux 内核,我们需要解决网卡适配的问题,但只需要适配一个网口即可,我们选择较为常用的 ENET2。
查看开发板的原理图和 LAN8720A 的芯片手册可知,ENET2 网卡 PHY 地址是 0x1
。
同时,根据 LAN8720A 的芯片手册,我们在使用前需要对其进行硬件复位和软件复位操作,其中硬件复位要保持 nRST 引脚持续拉低一段时间,软件复位要求向 Soft Reset bit of Basic Control Register 写入1
(建议多次写入直到其值为1)。
那我们继续修改配置文件configs/mx6ull_14x14_angus_emmc_defconfig
,删除以下代码(EVK 开发板的 PHY 芯片的生产厂商是 Micrel):
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ8XXX=y
使能 SMSC 公司的 PHY 驱动(LAN8720A 的生产厂商):
CONFIG_PHY_SMSC=y
修改文件arch/arm/dts/imx6ul-14x14-angus.dtsi
的对应项以关闭 ENET1 的初始化、配置 phy-reset-gpios
引脚以及设置phy-reset-duration
复位时间(对 LAN8720A 进行硬件复位):
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
status = "disabled";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-reset-gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
phy-reset-duration = <30>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@2 {
reg = <0>;
// micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET_REF>;
clock-names = "rmii-ref";
};
ethphy1: ethernet-phy@1 {
reg = <1>;
// micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET2_REF>;
clock-names = "rmii-ref";
};
};
};
pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x17059
>;
};
pinctrl_lcdif_ctrl: lcdifctrlgrp {
fsl,pins = <
MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79
MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79
MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79
MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79
/* used for lcd reset */
MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79
MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x79
>;
};
修改drivers/net/phy/phy.c
对 LAN8720A 进行软件复位(为了减小对其它芯片的影响,我们引入宏命令进行条件编译),由于这里修改的代码比较复杂,我们直接对比:
需要添加的代码如下:
#ifdef CONFIG_PHY_SMSC
int rc;
do{
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
udelay(100);
rc=phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
udelay(100);
}while(rc&BMCR_RESET);
#endif
#ifdef CONFIG_PHY_SMSC
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
udelay(1000);
#endif
适配 LCD 屏幕参数
修改arch/arm/dts/imx6ul-14x14-angus.dtsi
的对应项即可:
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat
&pinctrl_lcdif_ctrl>;
display = <&display0>;
status = "okay";
display0: display@0 {
bits-per-pixel = <24>;
bus-width = <24>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <51200000>;
hactive = <1024>;
vactive = <600>;
hfront-porch = <160>;
hback-porch = <140>;
hsync-len = <20>;
vback-porch = <20>;
vfront-porch = <12>;
vsync-len = <3>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
};
};
3. 编译、烧写 U-Boot 并启动开发板
编译:
make distclean
make mx6ull_14x14_angus_emmc_defconfig
make
烧写并启动开发板:
可以看出,U-Boot 已经成功在板子上运行起来,观察发现屏幕工作正常。
之后配置网络,以支持后续通过网络下载 Linux 内核及设备树、基于NFS 挂载根文件系统:
setenv ipaddr 10.10.10.31
setenv gatewayip 10.10.10.10
setenv netmask 255.255.0.0
setenv serverip 10.10.10.30
saveenv
如果 ENET2 未设置 MAC 地址,可以手动设置一下:
setenv eth1addr=00:01:3f:2d:3e:4d
saveenv
使用ping
命令检验:
=> ping 10.10.10.30
Using ethernet@20b4000 device
host 10.10.10.30 is alive
完工!
参考资料
[1] https://github.com/nxp-imx/uboot-imx/tree/imx_v2020.04_5.4.47_2.2.0
[2] https://gitee.com/weidongshan/uboot-imx
1 条评论
兄弟写的非常好