正点原子I.MX6U-MINI移植篇kernel移植过程详解
Posted 果果小师弟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正点原子I.MX6U-MINI移植篇kernel移植过程详解相关的知识,希望对你有一定的参考价值。
一、下载Linux内核
这里使用NXP官方提供的Linux源码,将其移植到正点原子I.MX6U-MINI开发板上。NXP官方原版Liux源码路径为:1、例程源码->4、NXP官方原版Uboot和Linux->linux-imx-rel_imx4.1.15_2.1.0_ga.tar.bz2。
在ubunut中的/home/zhiguoxin/linux/IMX6ULL/目录下创建一个nxp_kernel文件夹用于存放NXP的内核。使用FileZilla将其发送到Ubuntu中并解压,得到名为linux-imx-rel_imx4.1.15_2.1.0_ga的目录。
cd /home/zhiguoxin/linux/IMX6ULL/
mkdir nxp_kernel
cd nxp_kernel
tar -vxjf linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2
二、NXP官方开发板Linux内核编译
NXP提供的Linux源码肯定是可以在自己的I.MX6ULL EVK开发板上运行下去的,所以我们肯定是以I.MX6 ULL EVK开发板为参考,然后将Linux内核移植到I.MX6U-ALPHA开发板上的。
2.1 修改顶层Makefile
修改顶层Makefile,直接在顶层Makefile文件里面定义ARCH和CROSS COMPILE这两个的变量值为arm
和arm-linux-gnueabihf-
,结果如图所示:
2.2 配置并编译Linux内核
在编译 Linux 内核之前要先配置 Linux 内核。每个板子都有其对应的默认配置文件,这 些默认配置文件保存 在 arch/arm/configs 目录中。
imx_v7_defconfig 和imx_v7_mfg_defconfig 都可作为 I.MX6ULL EVK 开发板所使用的默认配置文件。但是这里建议使用 imx_v7_mfg_defconfig 这个默认配置文件,首先此配置文件默认支持 I.MX6UL 这款芯片,而且重要的一点就是此文件编译出来的 zImage 可以通过 NXP 官方提供的 MfgTool 工具烧写!!imx_v7_mfg_defconfig 中的“mfg”的意思就是 MfgTool。
进入到 Ubuntu 中的 Linux 源码根目录下,执行如下命令配置 Linux 内核:
make clean //第一次编译 Linux 内核之前先清理一下
make imx_v7_mfg_defconfig //配置 Linux 内核
配置完成以后就可以编译了,使用如下命令编译 Linux 内核:
make -j16 //编译 Linux 内核
等待编译完成,结果如图所示:
Linux 内核编译完成以后会在arch/arm/boot 目录下生成zImage镜像文件,如果使用设备树的话还会在 arch/arm/boot/dts 目录下开发板对应的.dtb(设备树)文件,比如imx6ull-14x14-evk.dtb就是 NXP 官方的I.MX6ULL EVK开发板对应的设备树文件。至此我们得到两个文件:
- ①、Linux内核镜像文件:zImage。
- ②、NXP官方 I.MX6ULL EVK开发板对应的设备树文件:imx6ull-14x14-evk.dtb。
2.3 Linux内核启动测试
在上面已经得到了 NXP 官方I.MX6ULL EVK 开发板对应的 zImage和imx6ull-14x14-evk.dtb 这两个文件。这两个文件能不能在正点原子的 I.MX6U-ALPHA EMMC 版开发板上启动呢?测试一下不就知道了。
在测试之前确保 uboot 中的环境变量bootargs内容如下:
console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw
使用命令
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv
将上一小节编译出来的zImage和imx6ull-14x14-evk.dtb复制到Ubuntu 中的tftp目录下,因为我们要在 uboot 中使用 tftp 命令将其下载到开发板中,拷贝命令如下:
cp arch/arm/boot/zImage /home/zhiguoxin/linux/tftp -f
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /home/zhiguoxin/linux/tftp -f
拷贝完成以后就可以测试了,启动开发板,进入uboot 命令行模式,然后输入如下命令将zImage 和 imx6ull-14x14-evk.dtb 下载到开发板中并启动:
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000
可以看出,此时Linux内核已经启动了。
三、在Linux中添加自己的开发板
通过编译NXP官方I.MX6ULL EVK 开发板对应的Linux内核,发现其可以在正点原子的EMMC版本开发板启动,所以我们就参考I.MX6ULL EVK开发板的设置,在Linux内核中添加正点原子的I.MX6U-ALPHA开发板。
3.1 添加开发板默认配置文件 件
将 arch/arm/configs目录下的imx_v7_mfg_defconfig重新复制一份 , 命名 为imx_alientek_emmc_defconfig,命令如下:
cd arch/arm/configs
cp imx_v7_mfg_defconfig imx_alientek_emmc_defconfig
以后imx_alientek_emmc_defconfig就是正点原子的EMMC版开发板默认配置文件了。完成以后如图所示:
以后就可以使用如下命令来配置正点原子EMMC版开发板对应的Linux内核了:
make imx_alientek_emmc_defconfig
3.2 添加开发板对应的设备树文件
添加适合正点原子 EMMC 版开发板的设备树文件,进入目录 arch/arm/boot/dts 中,复制一份 imx6ull-14x14-evk.dts,然后将其重命名为 imx6ull-alientek-emmc.dts,命令如下:
cd arch/arm/boot/dts
cp imx6ull-14x14-evk.dts imx6ull-alientek-emmc.dts
.dts是设备树源码文件,编译Linux的时候会将其编译为.dtb文件。imx6ull-alientek-emmc.dts创建好以后我们还需要修改文件arch/arm/boot/dts/Makefile, 找 到 “dtb-$(CONFIG_SOC_IMX6ULL)”配置项,在此配置项中加入“imx6ull-alientek-emmc.dtb” ,如下所示:
第422行为“imx6ull-alientek-emmc.dtb”,这样编译Linux 的时候就可以从 imx6ull-alientek-emmc.dts编译出 imx6ull-alientek-emmc.dtb文件了。
3.3 编译测试
创建一个编译脚本,imx6ull_alientek_emmc.sh,脚本内容如下:
touch imx6ull_alientek_emmc.sh
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
- 第2行,清理工程。
- 第3行,使用默认配置文件imx_alientek_emmc_defconfig来配置Linux内核。
- 第4行,打开Linux的图形配置界面,如果不需要每次都打开图形配置界面可以删除此行。
- 第5行,编译Linux。
执行shell脚本 imx6ull_alientek_emmc.sh编译Linux内核,命令如下:
chmod 777 imx6ull_alientek_emmc.sh //给予可执行权限
./imx6ull_alientek_emmc.sh //执行 shell 脚本编译内核
编译完成以后就会在目录arch/arm/boot下生成zImage镜像文件。在arch/arm/boot/dts目录下生成 imx6ull-alientek-emmc.dtb文件。将这两个文件拷贝到tftp目录下,
cp arch/arm/boot/zImage /home/zhiguoxin/linux/tftp -f
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /home/zhiguoxin/linux/tftp -f
然后重启开发板,在uboot命令模式中使用tftp命令下载这两个文件并启动,命令如下:
tftp 80800000 zImage
tftp 83000000 imx6ull-alientek-emmc.dtb
bootz 80800000 – 83000000
只要出现如图 所示内容就表示 Linux 内核启动成功:
Linux内核启动成功,说明我们已经在NXP提供的 Linux内核源码中添加了正点原子I.MX6UL-MINI开发板。
四、CPU主频和网络驱动修改
4.1 CPU主频修改
正点原子I.MX6U-MINI开发板所使用的 I.MX6ULL 芯片主频都是792MHz 的,也就是NXP官方宣传的800MHz版本。
1 、设置 I.MX6U-MINI开发板工作在792MHz
确保EMMC中的根文件系统可用!然后重新启动开发板,进入终端(可以输入命令),输入如下命令查看cpu信息:
cat /proc/cpuinfo
结果如图所示:
在图中有BogoMIPS这一条,此时 BogoMIIS 为 3.00,BogoMIPS是Linux 系统中衡量处理器运行速度的一个“尺子”,处理器性能越强,主频越高,BogoMIPS 值就越大。
BogoMIPS只是粗略的计算CPU性能,并不十分准确。但是我们可以通过 BogoMIPS 值来大致的判断当前处理器的性能。在图中并没有看到当前 CPU 的工作频率,那我们就转变另一种方法查看当前CPU的工作频率。
进入到目录/sys/bus/cpu/devices/cpu0/cpufreq中,此目录下会有很多文件,使用如下命令查看当前CPU频率:
cd /sys/bus/cpu/devices/cpu0/cpufreq
cat cpuinfo_cur_freq
4.2 使能8线EMMC驱动
正点原子EMMC版本核心板上的EMMC 采用的8位数据线,原理图如图所示:
Linux内核驱动里面 EMMC默是4线模式的,4线模式肯定没有8线模式的速度快,所以本节我们将EMMC的驱动修改为8线模式。
修改方法很简单,直接修改设备树即可,打开文件 imx6ull-alientek-emmc.dts,找到如下所示内容:
cd arch/arm/boot/dts
vi imx6ull-alientek-emmc.dts
&usdhc2
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
bus-width = <8>;
non-removable;
status = "okay";
;
修改完成以后保存一下 imx6ull-alientek-emmc.dts,然后使用命令make dtbs
重新编译一下设备树,编译完成以后使用新的设备树重启Linux 系统即可。
4.3 修改网络驱动
因为在后面学习Linux驱动开发的时候要用到网络调试驱动,所以必须要把网络驱动调试好。在讲解uboot移植的时候就已经说过了,正点原子开发板的网络和NXP官方的网络硬件上不同,网络PHY芯片由KSZ8081换为了 LAN8720A,两个网络 PHY芯片的复位IO也不同。所以Linux内核自带的网络驱动是驱动不起来I.MX6U-MINI开发板上的网络的,需要做修改。
4.3.1 修改LAN8720的复位以及网络时钟引脚驱动
ENET1复位引脚ENET1_RST连接在 I.M6ULL的SNVS_TAMPER7这个引脚上。ENET2的复位引脚 ENET2_RST 连接在I.MX6ULL 的SNVS_TAMPER8上。打开设备树文件imx6ull-alientek-emmc.dts,找到如下代码:
将 588 和 589 这两行删除掉!
删除掉以后继续在 imx6ull-alientek-emmc.dts 中找到如下所示代码,将示例代码中的第 129 行和第 133 行处的代码删除掉!!否则会干扰到网络复位引脚!
在 imx6ull-alientek-emmc.dts 里面找到名为“iomuxc_snvs”的节点(就是直接搜索),然后在此节点下添加网络复位引脚信息,添加完成以后的“iomuxc_snvs”的节点内容如下:
/*enet1 reset zhiguoxin*/
pinctrl_enet1_reset: enet1resetgrp
fsl,pins = <
/* used for enet1 reset */
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
>;
;
/*enet2 reset zhiguoxin*/
pinctrl_enet2_reset: enet2resetgrp
fsl,pins = <
/* used for enet2 reset */
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
>;
;
第 1 行,imx6ull-alientek-emmc.dts 文件中 iomuxc_snvs 节点。
第 559~600 行,ENET1 网络复位引脚配置信息。
第 603~608 行,ENET2 网络复位引脚配置信息。
最后还需要修改一下 ENET1 和 ENET2 的网络时钟引脚配置,继续在 imx6ull-alientek-emmc.dts 中找到如下所示代码
第 316和 331行,分别为 ENET1 和 ENET2 的网络时钟引脚配置信息,将这两个引脚的电气属性值改为0x4001b009,原来默认值为 0x4001b031。
修改完成以后记得保存一下 imx6ull-alientek-emmc.dts,网络复位以及时钟引脚驱动就修改好了。
4.3.2 修改fec1和fec2节点的pinctrl-0属性
在 imx6ull-alientek-emmc.dts 文件中找到名为“fec1”和“fec2”的这两个节点,修改其中的“pinctrl-0”属性值,修改以后如下所示:
4.3.3 修改LAN8720A的PHY地址
我们说过ENET1的LAN8720A地址为0x0,ENET2的LAN8720A地址为0x1。在 imx6ull-alientek-emmc.dts中找到如下代码:
- 第 171 和 172 行,添加了 ENET1 网络复位引脚所使用的IO为GPIO5_IO07,低电平有效。复位低电平信号持续时间为 200ms。
- 第 180 和 181 行,ENET2 网络复位引脚所使用的 IO 为 GPIO5_IO08,同样低电平有效,持续时间同样为 200ms。
- 第 191 和 197 行,“smsc,disable-energy-detect”表明 PHY 芯片是 SMSC 公司的,这样 Linux内核就会找到 SMSC 公司的 PHY 芯片驱动来驱动 LAN8720A。
- 第 190 行,注意“ethernet-phy@”后面的数字是 PHY 的地址,ENET1 的 PHY 地址为 0,所以“@”后面是 0(默认为 2)。
- 第 193 行,reg 的值也表示 PHY 地址,ENET1 的 PHY 地址为 0,所以 reg=0。
- 第 196 行,ENET2 的 PHY 地址为 1,因此“@”后面为 1。
- 第 199 行,因为 ENET2 的 PHY 地址为 1,所以 reg=1。
至此,LAN8720A 的 PHY 地址就改好了,保存一下 imx6ull-alientek-emmc.dts 文件。然后使用“make dtbs”命令重新编译一下设备树。
4.3.4 修改fec_main.c文件
要在I.MX6ULL上使用LAN8720A, 需要修改一下Linux内核源码 ,打开
drivers/net/ethernet/freescale/fec_main.c,找到函数fec_probe,在 fec_probe中加入如下代码:
cd drivers/net/ethernet/freescale
vi fec_main.c
/* 设置 MX6UL_PAD_ENET1_TX_CLK 和 MX6UL_PAD_ENET2_TX_CLK
* 这两个 IO 的复用寄存器的 SION 位为 1。
*/
void __iomem *IMX6U_ENET1_TX_CLK;
void __iomem *IMX6U_ENET2_TX_CLK;
IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC, 4);
writel(0X14, IMX6U_ENET1_TX_CLK);
IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC, 4);
writel(0X14, IMX6U_ENET2_TX_CLK);
第 3455~3462 就是新加入的代码,如果要在 I.MX6ULL 上使用 LAN8720A 就需要设置ENET1 和 ENET2 的 TX_CLK 引脚复位寄存器的 SION 位为1。
4.4.5 配置Linux内核,使能LAN8720驱动
输入命令“make menuconfig”,打开图形化配置界面,选择使能 LAN8720A 的驱动,路径如下:
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs
选择将Drivers for SMSC PHYs
编译到Linux内核中,因此<>
里面变为了*
。LAN8720A是SMSC公司出品的,因此勾选这个以后就会编译LAN8720驱动,配置好以后退出配置界面,然后重新编译一下Linux内核。
4.4.6 修改 smsc.c文件
在修改 smsc.c 文件之前先说点题外话,那就是我是怎么确定要修改 smsc.c 这个文件的。在写本书之前我并没有修改过 smsc.c 这个文件,都是使能 LAN8720A 驱动以后就直接使用。
但是我在测试 NFS 挂载文件系统的时候发现文件系统挂载成功率很低!老是提示NFS服务器找不到,三四次就有一次挂载失败!很折磨人。NFS 挂载就是通过网络来挂载文件系统,这样做的好处就是方便我们后续调试 Linux驱动。既然老是挂载失败那么可以肯定的是网络驱动有问题,网络驱动分两部分:内部MAC+外部 PHY,内部MAC驱动是由NXP提供的,一般不会出问题,否则的话用户早就给NXP反馈了。而且我用NXP官方的开发板测试网络是一直正常的,但是NXP官方的开发板所使用的PHY芯片为 KSZ8081。所以只有可能是外部PHY,也就是LAN8720A 的驱动可能出问题了。
鉴于LAN8720A 有“前车之鉴”,那就是在 uboot 中需要对LAN8720A 进行一次软复位,要设置 LAN8720A 的 BMCR(寄存器地址为 0)寄存器 bit15 为 1。所以我猜测,在 Linux 中也需要对 LAN8720A 进行一次软复位。
首先需要找到 LAN8720A 的驱动文件,LAN8720A 的驱动文件是 drivers/net/phy/smsc.c,在此文件中有个叫做 smsc_phy_reset 的函数,看名字都知道这是 SMSC PHY 的复位函数,因此,LAN8720A 肯定也会使用到这个复位函数,修改此函数的内容,修改以后的 smsc_phy_reset函数内容如下所示:
cd drivers/net/phy
vi smsc.c
static int smsc_phy_reset(struct phy_device *phydev)
int err, phy_reset;
int msec = 1;
struct device_node *np;
int timeout = 50000;
if(phydev->addr == 0) /* FEC1 */
np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@188000");
if(np == NULL)
return -EINVAL;
if(phydev->addr == 1) /* FEC2 */
np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@0b4000");
if(np == NULL)
return -EINVAL;
err = of_property_read_u32(np, "phy-reset-duration", &msec);
/* A sane reset duration should not be longer than 1s */
if (!err && msec > 1000)
msec = 1;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
if (!gpio_is_valid(phy_reset))
return;
gpio_direction_output(phy_reset, 0);
gpio_set_value(phy_reset, 0);
msleep(msec);
gpio_set_value(phy_reset, 1);
int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
if (rc < 0)
return rc;
/* If the SMSC PHY is in power down mode, then set it
* in all capable mode before using it.
*/
if ((rc & MII_LAN83C185_MODE_MASK) ==
MII_LAN83C185_MODE_POWERDOWN)
/* set "all capable" mode and reset the phy */
rc |= MII_LAN83C185_MODE_ALL;
phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
phy_write(phydev, MII_BMCR, BMCR_RESET);
/* wait end of reset (max 500 ms) */
do
udelay(10);
if (timeout-- == 0)
return -1;
rc = phy_read(phydev, MII_BMCR);
while (rc & BMCR_RESET);
return 0;
最后我们还需要在 drivers/net/phy/smsc.c 文件中添加两个头文件,因为修改后的smsc_phy_reset 函数用到了 gpio_direction_output 和gpio_set_value这两个函数,需要添加的头文件如下所示:
#include <linux/of_gpio.h>
#include <linux/io.h>
以上是关于正点原子I.MX6U-MINI移植篇kernel移植过程详解的主要内容,如果未能解决你的问题,请参考以下文章
正点原子I.MX6U-MINI移植篇u-boot移植过程详解
正点原子I.MX6U-MINI移植篇rootfs移植过程详解
正点原子I.MX6U-MINI移植篇rootfs移植过程详解
正点原子I.MX6U-MINI移植篇Ubuntu-base根文件系统移植构建过程详解