LV050-4-1-15版本移植
这部分是使用NXP的 Release rel_imx_4.1.15_2.1.0_ga: MLK-14762 ARM: dts: imx6sll-evk: correct gpio pin for lcd power control · nxp-imx/linux-imx · GitHub 这个版本内核进行移植,当时使用的Ubuntu22.04版本。
shellmake ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
一、添加开发板
1. 添加开发板默认配置文件
将 linux 内核源码目录中 arch/arm/configs 目录下的 imx_v7_mfg_defconfig 重新复制一份 , 命名 为 imx_alpha_emmc_defconfig:
cp arch/arm/configs/imx_v7_defconfig arch/arm/configs/imx_alpha_emmc_defconfig以后 imx_alpha_emmc_defconfig 就是正点原子的 EMMC 版开发板默认配置文件了。以后就可以使用如下命令来配置正点原子 EMMC 版开发板对应的 Linux 内核了
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alpha_emmc_defconfig2. 添加开发板对应的设备树文件
添加适合正点原子 EMMC 版开发板的设备树文件,进入目录 arch/arm/boot/dts 中,复制一份 imx6ull-14x14-evk.dts,然后将其重命名为 imx6ull-alpha-emmc.dts:
cp arch/arm/boot/dts/imx6ull-14x14-evk.dts arch/arm/boot/dts/imx6ull-alpha-emmc.dts.dts 是设备树源码文件,编译 Linux 的时候会将其编译为.dtb 文件。imx6ull-alpha-emmc.dts 创建好以后我们还需要修改文件 arch/arm/boot/dts/Makefile ,找 到 “ dtb-$(CONFIG_SOC_IMX6ULL)”配置项,在此配置项中加入“imx6ull-alpha-emmc.dtb” ,如下 所示 :
#......
imx6ull-14x14-evk-usb-certi.dtb \
imx6ull-alpha-emmc.dtb \
#......3. 编译测试
Linux 内核里面已经添加了正点原子 I.MX6UL-ALIPHA EMMC 版开发板了,接下接编译测试一下,我们可以创建一个编译脚本——1.sh,脚本内容如下 :
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alpha_emmc_defconfig
# make ARCH = arm CROSS_COMPILE = arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16然后我们执行此脚本就会开始编译内核和设备树文件,一般应该是没问题的,编译完成后我们可以得到如下两个文件:

4. 启动测试
编译完成以后就会在目录 arch/arm/boot 下生成 zImage 镜像文件。在 arch/arm/boot/dts 目录下生成 imx6ull-alpha-emmc.dtb 文件。将这两个文件拷贝到 tftp 目录下:
cp arch/arm/boot/zImage ~/3tftp/imx6ull/
cp arch/arm/boot/dts/imx6ull-alpha-emmc.dtb ~/3tftp/imx6ull/然后重启开发板(按照前边从 tftp 加载内核和设备树,从 nfs 挂载根文件系统,根文件系统可以先随便找一个能用的),在 uboot 命令模式中使用 tftp 命令下载这两个文件并启动,命令如下:
=> tftp 80800000 /imx6ull/zImage
=> tftp 83000000 /imx6ull/imx6ull-alpha-emmc.dtb
=> bootz 80800000 - 83000000 # 中间是一个 -然后应该可以正常启动:

我们可以看一下启动后的 linux:

会发现这里有报错,并且未成功加载根文件系统,这里就是说网络配置有问题,我们前边知道,ALPHA 使用的网络驱动与 NXP 官方的 EVK 评估板是不一样的,网络 PHY 芯片由 KSZ8081 换为了 LAN8720A,两个网络 PHY 芯片的复位 IO 也不同。所以 Linux 内核自带的网络驱动是驱动不起来 I.MX6U-ALPHA 开发板上的网络的,所以这里网口驱动其实是无法使用的,linux 无法通过网口来进行网络相关的活动,需要做修改。
二、修改网络驱动
1. 设备树修改
1.1 修改 LAN8720 的复位以及网络时钟引脚驱动
ENET1 复位引脚 ENET1_RST 连接在 I.M6ULL 的 SNVS_TAMPER7 这个引脚上。 ENET2 的复位引脚 ENET2_RST 连接在 I.MX6ULL 的 SNVS_TAMPER8 上。打开设备树文件 imx6ull-alpha-emmc.dts:

第 588 和 589 行就是初始化 SNVS_TAMPER7 和 SNVS_TAMPER8 这两个引脚的,不过看样子好像是作为了 SPI4 的 IO,这不是我们想要的,所以将 588 和 589 这两行删除掉。修改成如下所示代码:
pinctrl_spi4: spi4grp {
fsl,pins = <
MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1
MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1
>;
};删除掉以后继续在 imx6ull-apha-emmc.dts 中找到如下所示代码:

第 129 行,设置 GPIO5_IO08 为 SPI4 的一个功能引脚(我也不清楚具体作为什么功能用),而 GPIO5_IO08 就是 SNVS_TAMPER8 的 GPIO 功能引脚。
第 133 行,设置 GPIO5_IO07 作为 SPI4 的片选引脚,而 GPIO5_IO07 就是 SNVS_TAMPER7 的 GPIO 功能引脚。现在我们需要 GPIO5_IO07 和 GPIO5_IO08 分别作为 ENET1 和 ENET2 的复位引脚,而不是 SPI4 的什么功能引脚,因此将上图中的第 129 行和第 133 行处的代码删除掉,否则会干扰到网络复位引脚! 修改后如下所示:
spi4 {
compatible = "spi-gpio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi4>;
status = "disable";
gpio-sck = <&gpio5 11 0>;
gpio-mosi = <&gpio5 10 0>;
num-chipselects = <1>;
#address-cells = <1>;
#size-cells = <0>;
// ......
};在 imx6ull-alpha-emmc.dts 里面找到名为 “iomuxc_snvs” 的节点(就是直接搜索),然后在此节点下添加网络复位引脚信息,添加完成以后的 “ iomuxc_snvs ” 的节点内容如下:
&iomuxc_snvs {
pinctrl-names = "default_snvs";
pinctrl-0 = <&pinctrl_hog_2>;
imx6ul-evk {
//......
/*enet1 reset zuozhongkai*/
pinctrl_enet1_reset: enet1resetgrp {
fsl,pins = <
/* used for enet1 reset */
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
>;
};
/*enet2 reset zuozhongkai*/
pinctrl_enet2_reset: enet2resetgrp {
fsl,pins = <
/* used for enet2 reset */
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
>;
};
};
};最后还需要修改一下 ENET1 和 ENET2 的网络时钟引脚配置, 继续在 imx6ull-alpha-emmc.dts 中找到如下所示代码:

第 318 和 333 行, 分别为 ENET1 和 ENET2 的网络时钟引脚配置信息,将这两个引脚的电气属性值改为 0x4001b009,原来默认值为 0x4001b031。修改完成以后记得保存一下 imx6ull-alientek-emmc.dts,网络复位以及时钟引脚驱动就修改好了。
pinctrl_enet1: enet1grp {
fsl,pins = <
MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009
>;
};
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 0x4001b009
>;
};1.2 修改 fec1 和 fec2 节点的 pinctrl-0 属性
在 imx6ull-alpha-emmc.dts 文件中找到名为“fec1”和“fec2”的这两个节点,修改其中的“pinctrl-0”属性值,修改以后如下所示 :

&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_reset>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_reset>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
status = "okay";
// ......
};1.3 修改 LAN8720A 的 PHY 地址
在 uboot 移植章节中,我们知道 ENET1 的 LAN8720A 地址为 0x0, ENET2 的 LAN8720A 地址为 0x1。在 imx6ull-alpha-emmc.dts 中找到如下代码:

第 171~177 行, ENET1 对应的设备树节点。
第 179~200 行, ENET2 对应的设备树节点。但是第 186~198 行的 mdio 节点描述了 ENET1 和 ENET2 的 PHY 地址信息。将上图改为如下内容:
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1 &pinctrl_enet1_reset>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2 &pinctrl_enet2_reset>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
smsc,disable-energy-detect;
reg = <0>;
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
smsc,disable-energy-detect;
reg = <1>;
};
};
};修改的地方如下:

第 176 和 177 行,添加了 ENET1 网络复位引脚所使用的 IO 为 GPIO5_IO07,低电平有效。复位低电平信号持续时间为 200ms。
第 186 和 187 行, ENET2 网络复位引脚所使用的 IO 为 GPIO5_IO08,同样低电平有效,持续时间同样为 200ms。
第 196 和 202 行,“smsc, disable-energy-detect”表明 PHY 芯片是 SMSC 公司的,这样 Linux 内核就会找到 SMSC 公司的 PHY 芯片驱动来驱动 LAN8720A。
第 194 行,注意“ethernet-phy@”后面的数字是 PHY 的地址, ENET1 的 PHY 地址为 0,所以“@”后面是 0(默认为 2)。
第 197 行, reg 的值也表示 PHY 地址, ENET1 的 PHY 地址为 0,所以 reg = 0。
第 200 行, ENET2 的 PHY 地址为 1,因此“@”后面为 1。
第 203 行,因为 ENET2 的 PHY 地址为 1,所以 reg = 1。
1.4 设备树编译
至此, LAN8720A 的 PHY 地址就改好了,保存一下 imx6ull-alpha-emmc.dts 文件。然后使用以下命令重新编译一下设备树。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs # 只编译设备树编译完成后会有如下提示:

2. 内核源码修改
2.1 修改 fec_main.c 文件
要在 I.MX6ULL 上 使 用 LAN8720A , 需要修改一下 Linux 内核源码,打开 drivers/net/ethernet/freescale/fec_main.c,找到函数 fec_probe,在 fec_probe 中加入如下代码:

/* 设置 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);第 3452 ~ 3461 就是新加入的代码,如果要在 I.MX6ULL 上使用 LAN8720A 就需要设置 ENET1 和 ENET2 的 TX_CLK 引脚复位寄存器的 SION 位为 1。
2.2 配置 Linux 内核,使能 LAN8720 驱动
输入命令下边的命令:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig打开图形化配置界面,选择使能 LAN8720A 的驱动,路径如下:
.config - Linux/arm 4.1.15 Kernel Configuration
Device Drivers --->
[*] Network device support --->
-*- PHY Device support and infrastructure --->
< > Drivers for SMSC PHYs
选择将“ Drivers for SMSC PHYs ”编译到 Linux 内核中,因此“< >”里面变为了“ * ”。 LAN8720A 是 SMSC 公司出品的,因此勾选这个以后就会编译 LAN8720 驱动,配置好以后退出配置界面,然后重新编译一下 Linux 内核即可。
2.3 修改 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 函数内容如下所示:
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@02188000");
if(np == NULL)
{
return -EINVAL;
}
}
if(phydev->addr == 1) /* FEC2 */
{
np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000");
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;
}第 7~14 行,获取 FEC1 网卡对应的设备节点。
第 16~23 行,获取 FEC2 网卡对应的设备节点。
第 25 行,从设备树中获取“phy-reset-duration”属性信息,也就是复位时间。
第 29 行,从设备树中获取“phy-reset-gpios”属性信息,也就是复位 IO。
第 33~36 行,设置 PHY 的复位 IO,复位 LAN8720A。
第 45~52 行,以前的 smsc_phy_reset 函数会判断 LAN8720 是否处于 Powerdown 模式,只有处于 Powerdown 模式的时候才会软复位 LAN8720。这里我们将软复位代码移出来,这样每次调用 smsc_phy_reset 函数 LAN8720A 都会被软复位。最后我们还需要在 drivers/net/phy/smsc.c 文件中添加两个头文件,因为修改后的 smsc_phy_reset 函数用到了 gpio_direction_output 和 gpio_set_value 这两个函数,需要添加的头文件如下所示:
#include <linux/of_gpio.h>
#include <linux/io.h>3. 图形化配置文件处理
在修改网络驱动的时候我们通过图形界面使能了 LAN8720A 的驱动,使能以后会在.config 中存在如下代码:

打开 drivers/net/phy/Makefile,有如下代码:

当 CONFIG_SMSC_PHY = y 的时候就会编译 smsc.c 这个文件, smsc.c 就是 LAN8720A 的驱动文件。但是当我们执行“make distclean”清理工程以后.config 文件就会被删除掉,因此我们所有的配置内容都会丢失,结果就是前功尽弃!所以我们在配置完图形界面以后经过测试没有问题,就必须要保存一下配置文件,保存配置的方法有两个。
3.1 直接另存为.config 文件
既然图形化界面配置后的配置项保存在.config 中,那么我们就可以直接将.config 文件另存为 imx_alpha_emmc_defconfig,然后其复制到 arch/arm/configs 目录下,替换以前的 imx_alpha_emmc_defconfig 。这样以后执行“ make imx_alpha_emmc_defconfig”重新配置 Linux 内核的时候就会使用新的配置文件,默认就会使能 LAN8720A 的驱动。
cp .config arch/arm/configs/imx_alpha_emmc_defconfig3.2 通过图形界面保存配置文件
我们还有一种方式在图形界面中保存配置文件,在图形界面中会有“< Save >”选项,如图所示:
通过键盘的“→”键,移动到“< Save >”选项,然后按下回车键,打开文件名输入对话框,如图所示:

在图位置中输入要保存的文件名,可以带路径,一般是相对路径(相对于 Linux 内核源码根目录 )。比如我们要将新的配置文件保存到目录 arch/arm/configs 下,文件名为 imx_alpha_emmc_defconfig,也就是用新的配置文件替换掉老的默认配置文件。那么我们在图中输入“arch/arm/configs/imx_alpha_emmc_defconfig”即可:
arch/arm/configs/imx_alpha_emmc_defconfig
设置好文件名以后选择下方的“ < Ok >”按钮,保存文件并退出。退出以后再打开 arch/arm/configs/imx_alpha_emmc_defconfig 文件,就会在此文件中找到“CONFIG_SMSC_PHY = y”这一行:

同样的,使用“make imx_alientek_emmc_defconfig”重新配置 Linux 内核的时候, LAN8720A 的驱动就会使能,并被编译进 Linux 镜像文件 zImage 中。
4. 网口测试
4.1 文件准备
我们这里由于还要编译内核,所以直接使用下边的命令一步到位:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16编译完成后我们将设备树和 zImage 文件拷贝到 tftp 目录下:
cp arch/arm/boot/zImage ~/3tftp/imx6ull/
cp arch/arm/boot/dts/imx6ull-alpha-emmc.dtb ~/3tftp/imx6ull/修改好设备树和 Linux 内核以后重新编译一下,得到新的 zImage 镜像文件和 imx6ull-alpha-emmc.dtb 设备树文件,使用网线将 I.MX6U-ALPHA 开发板的两个网口与路由器或者电脑连接起来,最后使用新的文件启动 Linux 内核。
4.2 bootamd 与 bootargs
uboot 的这两个参数内容如下:
=> setenv bootcmd 'tftp 80800000 /imx6ull/zImage\;tftp 83000000 /imx6ull/imx6ull-alpha-emmc.dtb\;bootz 80800000 - 83000000'
=> setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs/imx6ull_rootfs,proto=tcp rw ip=192.168.10.102:192.168.10.101:192.168.10.1:255.255.255.0::eth0:off init=/linuxrc'
=> saveenv下边的 bootargs 其实就是给 linux 内核传递的参数,会配置好 IP 地址,并且从 NFS 挂载根文件系统。上边的 bootm 表示我们从 tftp 下载 zImage 和设备树。
4.2 启动测试
4.2.1 启动过程
若是网络驱动移植成功,并且有根文件系统的话就会正常挂载了(我这里用的是我自己移植的 busybox 根文件系统):
- (1)u-boot 启动

- (2)下载 zImage

- (3)下载设备树

- (4)启动内核

- (5)挂载 NFS 根文件系统

4.2.2 网络配置
启动以后使用“ifconfig -a”命令查看一下当前活动的网卡有哪些,结果如图所示:、
root@imx: /$ ifconfig -a
can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:27
can1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:28
eth0 Link encap:Ethernet HWaddr B8:AE:1D:01:00:00
inet addr:192.168.10.102 Bcast:192.168.10.255 Mask:255.255.255.0
inet6 addr: fe80::baae:1dff:fe01:0/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1785 errors:0 dropped:0 overruns:0 frame:0
TX packets:1299 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2052335 (1.9 MiB) TX bytes:167054 (163.1 KiB)
eth1 Link encap:Ethernet HWaddr B8:AE:1D:01:00:00
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
sit0 Link encap:IPv6-in-IPv4
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)中 can0 和 can1 为 CAN 接口的网卡, eth0 和 eth1 才是网络接口的网卡,其中 eth0 对应于 ENET2, eth1 对应于 ENET1。使用如下命令依次打开 eth0 和 eth1 这两个网卡:
ifconfig eth0 up
ifconfig eth1 up注意,我这里是接了 eth0,并且用于挂载根文件系统,所以它是直接启动的,要是连接了 eth1 的话可以用上边的命令启动网卡。我们可以通过以下命令配置开发板的 IP 地址:
ifconfig eth0 192.168.1.251
ifconfig eth1 192.168.1.252我们也可以使用 ping 命令来查看是否与同一网段的 ip 可以 ping 通:

三、dmesg显示时间戳
1. 为什么这么做?
我们移植好linux后,启动之后,使用dmesg打印日志的时候是这样的:
root@imx: /$ dmesg
Booting Linux on physical CPU 0x0
Linux version 4.1.15 (hk@vm) (gcc version 4.9.4 (Linaro GCC 4.9-2017.01) ) #1 SMP PREEMPT Sun Oct 23 22:17:07 CST 2022
CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: Freescale i.MX6 ULL 14x14 EVK Board
Reserved memory: created CMA memory pool at 0x8c000000, size 320 MiB
Reserved memory: initialized node linux,cma, compatible id shared-dma-pool
Memory policy: Data cache writealloc
On node 0 totalpages: 131072
free_area_init_node: node 0, pgdat 809e9bc0, node_mem_map 8bb57000
Normal zone: 1024 pages used for memmap
Normal zone: 0 pages reserved
Normal zone: 131072 pages, LIFO batch:31
// ... ...然后开发板出厂的时候打印的日志格式:
root@ATK-IMX6U:~# dmesg
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.1.15-g06f53e4 (alientek@ubuntu) (gcc version 5.3.0 (GCC) ) #1 SMP PREEMPT Sat Nov 27 18:39:27 CST 2021
[ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] Machine model: Freescale i.MX6 ULL 14x14 EVK Board
[ 0.000000] Reserved memory: created CMA memory pool at 0x98000000, size 128 MiB
[ 0.000000] Reserved memory: initialized node linux,cma, compatible id shared-dma-pool
// ... ...看起来好像整齐一些,后来查了查,前边的是时间戳,其实linux内核可以打开,只是默认是关闭的罢了。其实这样做是有好处的,我们可以看到开机在什么时间段做了什么事情。
2. 打开日志时间戳
我们进入linux内核源码目录,执行:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig然后找到如下配置项,配置为 * 。然后重新编译内核,从新编译的内核启动即可。
Kernel hacking --->
printk and dmesg options --->
[*] Show timing information on printks修改完毕后保存,重新编译内核即可。
3. 最终效果
root@imx: /$ dmesg
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.1.15 (hk@vm) (gcc version 4.9.4 (Linaro GCC 4.9-2017.01) ) #2 SMP PREEMPT Sun Nov 20 14:14:16 CST 2022
[ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] Machine model: Freescale i.MX6 ULL 14x14 EVK Board
[ 0.000000] Reserved memory: created CMA memory pool at 0x8c000000, size 320 MiB
[ 0.000000] Reserved memory: initialized node linux,cma, compatible id shared-dma-pool
[ 0.000000] Memory policy: Data cache writealloc
[ 0.000000] On node 0 totalpages: 131072
[ 0.000000] free_area_init_node: node 0, pgdat 809e9bc0, node_mem_map 8bb57000
[ 0.000000] Normal zone: 1024 pages used for memmap
[ 0.000000] Normal zone: 0 pages reserved
[ 0.000000] Normal zone: 131072 pages, LIFO batch:31
[ 0.000000] PERCPU: Embedded 12 pages/cpu @8bb31000 s16768 r8192 d24192 u49152
[ 0.000000] pcpu-alloc: s1676四、移植总结
关于 Linux 内核的移植就学习到这里,简单总结一下移植步骤:
(1)在 Linux 内核中查找可以参考的板子,一般都是半导体厂商自己做的开发板。
(2)编译出参考板子对应的 zImage 和.dtb 文件。
(3)使用参考板子的 zImage 文件和.dtb 文件在我们所使用的板子上启动 Linux 内核,看能否启动。
(4)如果能启动的话就万事大吉,如果不能启动那就悲剧了,需要调试 Linux 内核。不过一般都会参考半导体官方的开发板设计自己的硬件,所以大部分情况下都会启动起来。启动 Linux 内核用到的外设不多,一般就 DRAM(Uboot 都初始化好的)和串口。作为终端使用的串口一般都会参考半导体厂商的 Demo 板。
(5)修改相应的驱动,像 NAND Flash、 EMMC、 SD 卡等驱动官方的 Linux 内核都是已经提供好了,基本不会出问题。重点是网络驱动,因为 Linux 驱动开发一般都要通过网络调试代码,所以一定要确保网络驱动工作正常。如果是处理器内部 MAC+外部 PHY 这种网络方案的话,一般网络驱动都很好处理,因为在 Linux 内核中是有外部 PHY 通用驱动的。只要设置好复位引脚、 PHY 地址信息基本上都可以驱动起来。
(6)Linux 内核启动以后需要根文件系统,如果没有根文件系统的话肯定会崩溃,所以确定 Linux 内核移植成功以后就要开始根文件系统的构建。