【系统移植二】内核移植

1 编译NXP linux内核

1)源码路径:1、例程源码->4、NXP 官方原版Uboot和Linux->linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2

2)解压,重命名

tar -xvf linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2
mv linux-imx-rel_imx_4.1.15_2.1.0_ga linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek

1.1 编译内核

  1. 修改顶层Makefiel文件
    修改ARCHCROSS_COMPILE变量,大约在252行

    ARCH        ?= arm		
    CROSS_COMPILE   ?= arm-linux-gnueabihf-
    

    修改后就再编译的时候就不用输入很长的命令了。

  2. 配置并编译内核
    和uboot一样,在编译之前需要配置linux内核,配置文件保存在arch/arm/configs目录中。 imx_v7_defconfig 和imx_v7_mfg_defconfig 都是IMX6ULL的配置文件,区别是imx_v7_mfg_defconfig 可以使用MfgTool工具烧写。imx_v7_mfg_defconfig 中的“mfg”的意思就是 MfgTool。

    进入到 Ubuntu 中的 Linux 源码根目录下,执行如下命令配置 Linux 内核:

    make clean
    make imx_v7_mfg_defconfig
    make -j16
    

    编译完成之后会在arch/arm/boot目录下生成zImage镜像文件,在arch/arm/boot/dts目录下生成对应的.dtb(设备树)文件。

  3. 内核启动测试
    修改uboot中的环境变量bootargs,修改内容如下:

    setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
    

    将上面编译出来的zImage和imx6ull-14x14-evk.dtb复制到Ubuntu中的tftp目录下,命令如下:

    cp arch/arm/boot/zImage ~/linux/tftpboot/-f
    cp arch/arm/boot/dts/imux6ull-14x14-evk.dtb ~/linux/tftpboot/ -f
    

    启动开发板,进入uboot命令模式,输入如下命令:

    tftp 80800000 zImage
    tftp 83000000 imx6ull-14x14-evk.dtb
    bootz 80800000 - 83000000
    

    此时的内核是可以启动的,但是还是存在些问题,例如根文件的确实。

  4. 根文件系统确实错误
    修改bootargs环境变量,不启动跟文件。命令如下:

    setenv bootargs 'console=ttymxc0,115200' //设置bootargs
    saveenv //保存
    

    会在最后一行显示:
    Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
    也就是提示内核崩溃,因为 VFS(虚拟文件系统)不能挂载根文件系统,因为根文件系统目
    录不存在。

2 编译自己的内核

2.1 添加开发板的配置文件

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

2)在正点原子1.8的指导手册中,有如下内容:
在这里插入图片描述
但是在代码中并没有找到该内容,搜索结果如下:
在这里插入图片描述
均没有在311行左右的。所以暂时先这样,没有修改,也没有发现问题,可能是内核版本不同。

2.2 添加开发板对应的设备树文件

1)进入目录 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

添加如下内容:
在这里插入图片描述
注意:\后面不能有空格,否则编译会报错

2.3 编译测试:

在测试之前需要保证开发版的emmc中操作系统,并且根文件系统可用。如果没有,可以使用MfgTool工具下载,开发板emmc启动的时候一定要用电源线连接开发板,否则可能会启动不起来。

1)编写脚本,编译代码,脚本内容如,脚本要有可执行权限:

#!/bin/bash
make ARCH=arm CROSS_COMPLIE=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

编译过程中会出现图形配置界面,直接按两次esc按键退出即可。编译过程比较久,耐心等待。
编译成功会出现下图中的内容:
在这里插入图片描述
表示zImage编译成功

2)拷贝zImage和imx6ull-alientek-emmc.dtb到tftpboot目录下,(tftp服务器设置可以参考NFS和TFTP服务器搭建)。在下载两个文件并启动,命令如下:

cp arch/arm/boot/zImage ~/linux/tftpboot/
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb ~/linux/tftpboot/

3)启动开发板
因为我设置了uboot的环境变量bootcmd=tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000,所以复位开发板后,可以自动从tftp下载镜像和设备树。

若没有设置上面的环境变量,则进入uboot的命令模式,用下面命令启动开发板。(用词可能不准确,就是在倒数是时间结束前,按下回车键,进入的模式)

tftp 80800000 zImage
tftp 83000000 imx6ull-alientek-emmc.dtb
bootz 80800000 - 83000000

此时正常情况下是可以启动起来的,如果显示没有根文件系统,可以查看下bootargs设置是否正确。
我的这个开发板总是显示ipv6连接有问题,不知道是什么原因。(猜测是因为网络还没有修改)
在这里插入图片描述

2.4 使能8线emmc驱动

1)修改文件
修改emmc的驱动为8根线,修改方式很简单,直接修改设备树文件即可,打开imx6ull-alientek-emmc.dts,找到如下内容:

&usdhc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc2>;
 	non-removable;
	status = "okay";
};

修改为如下内容:

&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-14x14-evk-emmc.dts,将里面的内容复制过去就好了。imx6ull-14x14-evk-emmc.dts中的内容如下:
在这里插入图片描述
2)编译设备树文件

make dtbs

成功编译如下图所示:
在这里插入图片描述

编译完成后,将新编译的设备树文件拷贝到tftpboot目录下,重新启动开发板。

2.5 cpu主频修改

2.5.1 查看CPU信息

  1. 查看CPU基本信息

    1. 使用命令:cat /proc/cpuinfo,结果如图所示
      在这里插入图片描述
      BogoMIPS是linux系统中衡量处理器性能的“尺子”,处理器能力越强,主频越高,BogoMIPS值就越大。
  2. 查看CPU工作频率
    进入到目录/sys/bus/cpu/devices/cpu0/cpufreq,该目录下有很多文件,如图所示:
    在这里插入图片描述
    此目录中记录了CPU频率信息,(简单介绍个其余以后补充)
    1)cpuinfo_cur_freq:当前CPU工作频率
    2) scaling_governor:当前调频策略

    查看cpu当前频率:
    cat cpuinfo_cur_freq
    
  3. 查看CPU在各频率下工作的时间
    命令:cat /sys/bus/cpu/devices/cpu0/cpufreq/stats/time_in_state

2.5.2 图形化修改调频策略

  1. 命令:make menuconfig
    终端窗口一定要够大,不然会报错,无法使用界面修改调频策略(一般情况下不会出现这种情况)。界面形式如下图:
    在这里插入图片描述

  2. 配置路径

    CPU Power Management
    	-> CPU Frequency scaling
    		-> CPU Frequency scaling
    			-> Default CPUFreq governor
    

    CPU调频选择界面如图所示:
    在这里插入图片描述
    选择performance模式,选择后退出配置界面,编译linux内核,注意,一定不要清理工程,在这个地方不能使用之前的脚本编译,否则配置会没有效果。
    调频策略:
    ①、Performance,最高性能,直接用最高频率,不考虑耗电。
    ②、Interactive,一开始直接用最高频率,然后根据 CPU 负载慢慢降低。
    ③、Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个!
    ④、Userspace,可以在用户空间手动调节频率。
    ⑤、Ondemand,定时检查负载,然后根据负载来调节频率。负载低的时候降低 CPU 频率,

2.6 网络修改

正点原子开发板使用的网络芯片LAN8720,所以需要修改网络驱动

2.6.1 修改LAN8720复位引脚

修改imx6ull-alientek-emmc.dts文件

  1. 修改pinctrl_spi4
    ENET1复位引脚连接在I.MX6ULL的 SNVS_TAMPER7 这个引脚上。ENET2的复位引脚 ENET2_RST 连接在 I.MX6ULL的 SNVS_TAMPER8 上。所以需要将这两个引脚与网络部分相连,不能在用于对spi的控制。找到下面代码:

    584         pinctrl_spi4: spi4grp {
    585                         fsl,pins = <
    586                                 MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10        0x70a1
    587                                 MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11        0x70a1
    588                                /* MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07      0x70a1 */
    589                                /* MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08      0x80000000 */
    590                         >;
    591                 };
    

    注释掉与GPIO5_IO07和GPIO5_IO08相关代码,即注释588和589两行。

  2. 修改spi4
    找到下面代码,同样注释与GPIO5_IO07和GPIO5_IO08相关代码。注释129和133行。注释完结果如下:

    125     spi4 {
    126         compatible = "spi-gpio";
    127         pinctrl-names = "default";
    128         pinctrl-0 = <&pinctrl_spi4>;
    129     /*  pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;*/
    130         status = "okay";
    131         gpio-sck = <&gpio5 11 0>;
    132         gpio-mosi = <&gpio5 10 0>;
    133     /*  cs-gpios = <&gpio5 7 0>;*/
    134         num-chipselects = <1>;
    135         #address-cells = <1>;
    136         #size-cells = <0>;
    137 
    138         gpio_spi: gpio_spi@0 {
    139             compatible = "fairchild,74hc595";
    140             gpio-controller;
    141             #gpio-cells = <2>;
    142             reg = <0>;
    143             registers-number = <1>;
    144             registers-default = /bits/ 8 <0x57>;
    145             spi-max-frequency = <100000>;
    146         };
    147     };
    
  3. 修改网络部分princtrl_enet1pinctrl_enet2
    找到这两部分代码(大约在309行),做如下修改:

    309         pinctrl_enet1: enet1grp {
    310             fsl,pins = <
    311                 MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN  0x1b0b0
    312                 MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER  0x1b0b0
    313                 MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
    314                 MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
    315                 MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN  0x1b0b0
    316                 MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
    317                 MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
    318                 MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b031
    319                MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0/* ENET1 RESET */
    320             >;
    321         };
    322 
    323         pinctrl_enet2: enet2grp {
    324             fsl,pins = <
    325                 MX6UL_PAD_GPIO1_IO07__ENET2_MDC     0x1b0b0
    326                 MX6UL_PAD_GPIO1_IO06__ENET2_MDIO    0x1b0b0
    327                 MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN  0x1b0b0
    328                 MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER  0x1b0b0
    329                 MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
    330                 MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
    331                 MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN  0x1b0b0
    332                 MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
    333                 MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
    334                 MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2  0x4001b031
    335                 MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0 /* ENET2 RESET */
    336             >;
    337         };
    

    第 319 行,ENET1 复位引脚 SNVS_TAMPER7 的配置代码。
    第 335 行,ENET2 复位引脚 SNVS_TAMPER8 的配置代码

上面三部分全部改完之后,保存退出。

2.6.2 修改LAN8720的PHY地址

ENEN1的LAN8720地址为0x0,ENET2的LA8720的地址0x1。在imx6ull-alientek-emmc.dts中找到&fec1&fec2部分代码,修改为如下:

&fec1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_enet1>;
    phy-mode = "rmii";
    phy-handle = <&ethphy0>;
    phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;		// 新添加内容
    phy-reset-duration = <200>;							// 新添加内容
    status = "okay";
};

&fec2 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_enet2>;
    phy-mode = "rmii";
    phy-handle = <&ethphy1>;
    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 {								// 将2 改为 0 
            compatible = "ethernet-phy-ieee802.3-c22";
            smsc,disable-energy-detect;							// 新添加内容
            reg = <0>;											// 将2 改为 0 
        };

        ethphy1: ethernet-phy@1 {
            compatible = "ethernet-phy-ieee802.3-c22";
            smsc,disable-energy-detect;						// 新添加内容
            reg = <1>;
        };
    };
};

2.6.3 修改fec_main.c文件

要在imx6ull上使用LAN8720,需要修改一下linux内核源码,打开drivers/net/ethernet/fen_main.c,找到fec_prob函数,在该函数中加入下面代码:

static int
fec_probe(struct platform_device *pdev)
{
	struct fec_enet_private *fep;
	struct fec_platform_data *pdata;
	struct net_device *ndev;
	int i, irq, ret = 0;
	struct resource *r;
	const struct of_device_id *of_id;
	static int dev_id;
	struct device_node *np = pdev->dev.of_node, *phy_node;
	int num_tx_qs;
	int num_rx_qs;

    /* 设置 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);					// 新添加内容

	fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
......	
}

2.6.4 配置linux内核,使能LAN8720驱动

输入命令make menuconfig打开图形化配置界面,使能LAN8720驱动。

-> Device Drivers
	-> Network device support
		-> PHY Device support and infrastructure
			-> Drivers for SMSC PHYs

配置好图形界面后可以在.confing文件中看到CONFIG_SMSC_PHY被使能
在这里插入图片描述
/drivers/net/phy/Makefile文件中有如下代码:
在这里插入图片描述

注:

  1. 当我们执行“make clean”清理工程以后.config 文件就会被删除掉,因此我们所有的配置内容都会丢失,结果就是前功尽弃,一“删”回到解放前!所以我们在配置完图形界面以后经过测试没有问题,就必须要保存一下配置文件

2.6.5 修改smsc.c

修改这个文件的原因是:NFS挂在成功率低,老师提示NFS服务器找不到。
找到LAN8720的驱动文件,dreivers/net/phy/smsc.c
1)修改函数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;
}

以前的 smsc_phy_reset 函数会判断 LAN8720 是否处于 Powerdown 模式,只有处于 Powerdown 模式的时候才会软复位 LAN8720。这里我们将软复位代码移出来,这样每次调用 smsc_phy_reset 函数 LAN8720A 都会被软复位

2)在添加两个头文件

#include <linux/of_gpio.h>
#include <linux/io.h>

2.6.6 测试网络

  1. 重新编译内核,执行如下命令

    make dtbs
    make
    

    因为使用了图形化配置,所以不要实用脚本配置,脚本中的make distclean会清除配置。
    将新编译出来的镜像和设备树文件下载到开发板

  2. 打开网卡

     ifconfig eth0 up
     ifconfig eth1 up
    
  3. 配置IP地址

     ifconfig eth0 192.168.0.100
     ifconfig eth1 192.168.0.101
    

eth1的网络连接总间断,eth2的没有问题

  • 13
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值