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 编译内核
-
修改顶层Makefiel文件
修改ARCH
和CROSS_COMPILE
变量,大约在252行ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabihf-
修改后就再编译的时候就不用输入很长的命令了。
-
配置并编译内核
和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
(设备树)文件。 -
内核启动测试
修改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
此时的内核是可以启动的,但是还是存在些问题,例如根文件的确实。
-
根文件系统确实错误
修改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信息
-
查看CPU基本信息
- 使用命令:
cat /proc/cpuinfo
,结果如图所示
BogoMIPS
是linux系统中衡量处理器性能的“尺子”,处理器能力越强,主频越高,BogoMIPS值就越大。
- 使用命令:
-
查看CPU工作频率
进入到目录/sys/bus/cpu/devices/cpu0/cpufreq
,该目录下有很多文件,如图所示:
此目录中记录了CPU频率信息,(简单介绍个其余以后补充)
1)cpuinfo_cur_freq:当前CPU工作频率
2) scaling_governor:当前调频策略查看cpu当前频率: cat cpuinfo_cur_freq
-
查看CPU在各频率下工作的时间
命令:cat /sys/bus/cpu/devices/cpu0/cpufreq/stats/time_in_state
2.5.2 图形化修改调频策略
-
命令:
make menuconfig
终端窗口一定要够大,不然会报错,无法使用界面修改调频策略(一般情况下不会出现这种情况)。界面形式如下图:
-
配置路径
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
文件
-
修改
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两行。 -
修改
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 };
-
修改网络部分
princtrl_enet1
和pinctrl_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 = <ðphy0>;
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 = <ð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 { // 将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
文件中有如下代码:
注:
- 当我们执行“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 测试网络
-
重新编译内核,执行如下命令
make dtbs make
因为使用了图形化配置,所以不要实用脚本配置,脚本中的
make distclean
会清除配置。
将新编译出来的镜像和设备树文件下载到开发板 -
打开网卡
ifconfig eth0 up ifconfig eth1 up
-
配置IP地址
ifconfig eth0 192.168.0.100 ifconfig eth1 192.168.0.101
eth1的网络连接总间断,eth2的没有问题