2)摘自《正点原子I.MX6U嵌入式Linux驱动开拓指南》
关注官方微旗子暗记"大众年夜众号,获取更多资料:正点原子
第三十七章Linux内核移植

前两章我们大略理解了一下Linux内核顶层Makefile和Linux内核的启动流程,本章我们就来学习一下如何将NXP官方供应的Linux内核移植到正点原子的I.MX6U-ALPHA开拓板上。通过本章的学习,我们将节制如何将半导体厂商供应的Linux BSP包移植到我们自己的平台上。
37.1 创建VSCode工程
这里我们利用NXP官方供应的Linux源码,将其移植到正点原子I.MX6U-ALPHA开拓板上。NXP官方原版Linux源码已经放到了开拓板光盘中,路径为:1、例程源码->4、NXP官方原版Uboot和Linux->linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。利用FileZilla将其发送到Ubuntu中并解压,得到名为linux-imx-rel_imx_4.1.15_2.1.0_ga的目录,为了和NXP官方的名字区分,可以利用“mv”命令对其重命名,我这里将其重命名为“linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek”,命令如下:
mv linux-imx-rel_imx_4.1.15_2.1.0_ga linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
完成往后创建VSCode工程,步骤和Windows下一样,重点是.vscode/settings.json这个文件。
37.2 NXP官方开拓板Linux内核编译NXP供应的Linux源码肯定是可以在自己的I.MX6ULL EVK开拓板上运行下去的,以是我们肯定因此I.MX6ULL EVK开拓板为参考,然后将Linux内核移植到I.MX6U-ALPHA开拓板上的。
37.2.1修正顶层Makefile修正顶层Makefile,直接在顶层Makefile文件里面定义ARCH和CROSS_COMPILE这两个的变量值为arm和arm-linux-gnueabihf-,结果如图37.2.1所示:
图37.2.1 修正顶层Makefile
图37.2.1中第252和253行分别设置了ARCH和CROSS_COMPILE这两个变量的值,这样在编译的时候就不用输入很长的命令了。
37.2.2 配置并编译Linux内核和uboot一样,在编译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内核
配置完成往后如图37.2.2.1所示:
图37.2.2.1 配置Linux内核
配置完成往后就可以编译了,利用如下命令编译Linux内核:
make-j16 //编译Linux内核
等待编译完成,结果如图37.2.2.2所示:
图37.2.2.2 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。
37.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
将上一小节编译出来的zImage和imx6ull-14x14-evk.dtb复制到Ubuntu中的tftp目录下,由于我们要在uboot中利用tftp命令将其下载到开拓板中,拷贝命令如下:
cp arch/arm/boot/zImage /home/zuozhongkai/linux/tftpboot/ -f
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /home/zuozhongkai/linux/tftpboot/ -f
拷贝完成往后就可以测试了,启动开拓板,进入uboot命令行模式,然后输入如下命令将zImage和imx6ull-14x14-evk.dtb下载到开拓板中并启动:
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 – 83000000
结果图37.2.3.1所示:
图37.2.3.1 启动Linux内核
从图37.2.3.1可以看出,此时Linux内核已经启动了,如果EMMC中的根文件系统存在,我们就可以进入到Linux系统里面利用命令进行操作如图37.2.3.2所示:
图37.2.3.2 进入Linux根文件系统
37.2.4 根文件系统缺失落缺点Linux内核启动往后是须要根文件系统的,根文件系统存在哪里是由uboot的bootargs环境变量指定,bootargs会通报给Linux内核作为命令行参数。比如上一小节设置root=/dev/mmcblk1p2,也便是说根文件系统存储在/dev/mmcblk1p2中,也便是EMMC的分区2中。这是由于正点原子的EMMC版本开拓板出厂的时候已经EMMC的分区2中烧写好了根文件系统,以是设置root=/dev/mmcblk1p2。如果我们不设置根文件系统路径,或者说根文件系统路径设置缺点的话会涌现什么问题?这个问题是很常见的,我们在实际的事情中开拓一个产品,这个产品的初版硬件出来往后我们是没有对应的根文件系统可用的,必须要自己做根文件系统。在构建出对应的根文件系统之前Linux内核是没有根文件系统可用的,此时Linux内核启动往后会涌现什么问题呢?带着这个问题,我们将uboot中的bootargs环境变量改为“console=ttymxc0,115200”,也便是不填写root的内容了,命令如下:
setenv bootargs 'console=ttymxc0,115200'
修正完成往后重新从网络启动,启动往后会有如图37.2.4.1所示缺点:
图37.2.4.1 根文件系统缺失落缺点
在图37.2.4.1中末了会有下面这一行:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
也便是提示内核崩溃,由于VFS(虚拟文件系统)不能挂载根文件系统,由于根文件系统目录不存在。纵然根文件系统目录存在,如果根文件系统目录里面是空的依旧会提示内核崩溃。这个便是根文件系统缺失落导致的内核崩溃,但是内核是启动了的,只是根文件系统不存在而已。
37.3 在Linux中添加自己的开拓板在37.2小节中我们通过编译NXP官方I.MX6ULL EVK开拓板对应的Linux内核,创造其可以在正点原子的EMMC版本开拓板启动,以是我们就参考I.MX6ULL EVK开拓板的设置,在Linux内核中添加正点原子的I.MX6U-ALPHA开拓板。
37.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版开拓板默认配置文件了。完成往后如图37.3.1.1所示:
图37.3.1.1 新添加的默认配置文件
往后就可以利用如下命令来配置正点原子EMMC版开拓板对应的Linux内核了:
makeimx_alientek_emmc_defconfig
37.3.2 添加开拓板对应的设备树文件添加适宜正点原子EMMC版开拓板的设备树文件,进入目录arch/arm/boot/dts中,复制一份imx6ull-14x14-evk.dts,然后将其重命名为imx6ull-alientek-emmc.dts,命令如下:
cdarch/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”,如下所示:
示例代码37.3.2.1 arch/arm/boot/dts/Makefile代码段
400 dtb-$(CONFIG_SOC_IMX6ULL)+= \
401 imx6ull-14x14-ddr3-arm2.dtb \
402 imx6ull-14x14-ddr3-arm2-adc.dtb \
403 imx6ull-14x14-ddr3-arm2-cs42888.dtb \
404 imx6ull-14x14-ddr3-arm2-ecspi.dtb \
405 imx6ull-14x14-ddr3-arm2-emmc.dtb \
406 imx6ull-14x14-ddr3-arm2-epdc.dtb \
407 imx6ull-14x14-ddr3-arm2-flexcan2.dtb \
408 imx6ull-14x14-ddr3-arm2-gpmi-weim.dtb \
409 imx6ull-14x14-ddr3-arm2-lcdif.dtb \
410 imx6ull-14x14-ddr3-arm2-ldo.dtb \
411 imx6ull-14x14-ddr3-arm2-qspi.dtb \
412 imx6ull-14x14-ddr3-arm2-qspi-all.dtb \
413 imx6ull-14x14-ddr3-arm2-tsc.dtb \
414 imx6ull-14x14-ddr3-arm2-uart2.dtb \
415 imx6ull-14x14-ddr3-arm2-usb.dtb \
416 imx6ull-14x14-ddr3-arm2-wm8958.dtb \
417 imx6ull-14x14-evk.dtb \
418 imx6ull-14x14-evk-btwifi.dtb \
419 imx6ull-14x14-evk-emmc.dtb \
420 imx6ull-14x14-evk-gpmi-weim.dtb \
421 imx6ull-14x14-evk-usb-certi.dtb \
422 imx6ull-alientek-emmc.dtb \
423 imx6ull-9x9-evk.dtb \
424 imx6ull-9x9-evk-btwifi.dtb \
425 imx6ull-9x9-evk-ldo.dtb
第422行为“imx6ull-alientek-emmc.dtb”,这样编译Linux的时候就可以从imx6ull-alientek-emmc.dts编译出imx6ull-alientek-emmc.dtb文件了。
37.3.3 编译测试经由37.3.1和37.3.2两个小节,Linux内核里面已经添加了正点原子I.MX6UL-ALIPHA EMMC版开拓板了,接下接编译测试一下,我们可以创建一个编译脚本,imx6ull_alientek_emmc.sh,脚本内容如下:
示例代码37.3.2.1 imx6ull_alientek_emmc.sh编译脚本
1 #!/bin/sh
2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
4 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
5 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内核,编译完成往后就会在目录arch/arm/boot下天生zImage镜像文件。在arch/arm/boot/dts目录下天生imx6ull-alientek-emmc.dtb文件。将这两个文件拷贝到tftp目录下,然后重启开拓板,在uboot命令模式中利用tftp命令下载这两个文件并启动,命令如下:
tftp 80800000 zImage
tftp 83000000 imx6ull-alientek-emmc.dtb
bootz 80800000 – 83000000
只要涌现如图37.3.3.1所示内容就表示Linux内核启动成功:
图37.3.3.1 Linux内核启动
Linux内核启动成功,解释我们已经在NXP供应的Linux内核源码中添加了正点原子I.MX6UL-ALPHA开拓板。
37.4 CPU主频和网络驱动修正37.4.1 CPU主频修正1、设置I.MX6U-ALPHA开拓板事情在528MHz
确保EMMC中的根文件系统可用!
然后重新启动开拓板,进入终端(可以输入命令),如图37.4.1.1所示:
图37.4.1.1 进入命令行
进入图37.4.1所示的命令行往后输入如下命令查看cpu信息:
cat /proc/cpuinfo
结果如图37.4.2所示:
图37.4.1.2 cpu信息
在图37.4.2.1中有BogoMIPS这一条,此时BogoMIIS为3.00,BogoMIPS是Linux系统中衡量处理器运行速率的一个“尺子”,处理器性能越强,主频越高,BogoMIPS值就越大。BogoMIPS只是粗略的打算CPU性能,并不十分准确。但是我们可以通过BogoMIPS值来大致的判断当前处理器的性能。在图37.4.1.2中并没有看到当前CPU的事情频率,那我们就转变另一种方法查看当前CPU的事情频率。进入到目录/sys/bus/cpu/devices/cpu0/cpufreq中,此目录下会有很多文件,如图37.4.1.3所示:
图37.4.1.3 cpufreq目录
此目录中记录了CPU频率等信息,这些文件的含义如下:
cpuinfo_cur_freq:当前cpu事情频率,从CPU寄存器读取到的事情频率。
cpuinfo_max_freq:处理器所能运行的最高事情频率(单位: KHz)。
cpuinfo_min_freq:处理器所能运行的最低事情频率(单位: KHz)。
cpuinfo_transition_latency:处理器切换频率所须要的韶光(单位:ns)。
scaling_available_frequencies:处理器支持的主频率列表(单位: KHz)。
scaling_available_governors:当前内核中支持的所有governor(调频)类型。
scaling_cur_freq:保存着cpufreq模块缓存确当前CPU频率,不会对CPU硬件寄存器进行检讨。
scaling_driver:该文件保存当前CPU所利用的调频驱动。
scaling_governor:governor(调频)策略,Linux内核一共有5中调频策略,
①、Performance,最高性能,直接用最高频率,不考虑耗电。
②、Interactive,一开始直接用最高频率,然后根据CPU负载逐步降落。
③、Powersave,省电模式,常日以最低频率运行,系统性能会受影响,一样平常不会用这个!
④、Userspace,可以在用户空间手动调节频率。
⑤、Ondemand,定时检讨负载,然后根据负载来调节频率。负载低的时候降落CPU频率,这样省电,负载高的时候提高CPU频率,增加性能。
scaling_max_freq:governor(调频)可以调节的最高频率。
cpuinfo_min_freq:governor(调频)可以调节的最低频率。
stats目录下给出了CPU各种运行频率的统计情形,比如CPU在各频率下的运行韶光以及变频次数。
利用如下命令查看当前CPU频率:
cat cpuinfo_cur_freq
结果如图37.4.1.4所示:
图37.4.1.4 当前CPU频率
从图37.4.1.4可以看出,当前CPU频率为198MHz,事情频率很低!
其他的值如下:
cpuinfo_cur_freq = 198000
cpuinfo_max_freq = 528000
cpuinfo_min_freq = 198000
scaling_cur_freq = 198000
scaling_max_freq = 528000
cat scaling_min_freq = 198000
scaling_available_frequencies = 198000 396000 528000
cat scaling_governor = ondemand
可以看出,当前CPU支持198MHz、396MHz和528Mhz三种频率切换,个中调频策略为ondemand,也便是定期检讨负载,然后根据负载情形调节CPU频率。由于当前我们开拓板并没有做什么事情,因此CPU频率降落为198MHz以省电。如果开拓板做一些高负载的事情,比如播放视频、播放视频等操作那么CPU频率就会提升上去。查看stats目录下的time_in_state文件可以看到CPU在各频率下的事情韶光,命令如下:
cat /sys/bus/cpu/devices/cpu0/cpufreq/stats/time_in_state
结果如图37.4.1.5所示:
图37.4.1.5 CPU运行频率统计
从图37.4.1.5中可以看出,CPU在198MHz、396MHz和528MHz都事情过,个中198MHz的事情韶光最长!
如果我们想让CPU一贯事情在528MHz那该怎么办?很大略,配置Linux内核,将调频策略选择为performance。或者修正imx_alientek_emmc_defconfig文件,此文件中有下面几行:
示例代码37.4.1.1 调频策略
41 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
42 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
43 CONFIG_CPU_FREQ_GOV_USERSPACE=y
44 CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
第41行,配置ondemand为默认调频策略。
第42行,使能powersave策略。
第43行,使能userspace策略。
第44行,使能interactive策略。
将示例代码37.4.1.1中的第41行屏蔽掉,然后在44行后面添加:
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
结果下所示:
示例代码37.4.1.2 修正调频策略
41 #CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
42 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
43 CONFIG_CPU_FREQ_GOV_USERSPACE=y
44 CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
45 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
修正完成往后重新编译Linux内核,编译之前先清理一下工程!
由于我们重新修正过默认配置文件了,编译完成往后利用新的zImage镜像文件重新启动Linux。再次查看/sys/devices/system/cpu/cpu0/cpufreq/ cpuinfo_cur_freq文件的值,如图37.4.1.6所示:
图37.4.1.6 当前CPU频率
从图37.4.1.6可以看出,当前CPU频率为528MHz了。查看scaling_governor文件看一下当前的调频策略,如图37.4.1.7所示:
图37.4.1.7 调频策略
从图37.4.1.7可以看出当前的CPU调频策略为preformance,也便是高性能模式,一贯以最高主频运行。
我们再来看一下如何通过图形化界面配置Linux内核的CPU调频策略,输入“makemenuconfig”打开Linux内核的图形化配置界面,如图37.4.1.8所示:
图37.4.1.8 Linux内核图形化配置界面
进入如下路径:
CPU Power Management
-> CPU Frequency scaling
-> CPU Frequency scaling
-> Default CPUFreq governor
打开默认调频策略选择界面,选择“performance”,如图37.1.4.9所示:
图37.1.4.9 默认调频策略选择
在图37.1.4.9中选择“performance”即可,选择往后退出图形化配置界面,然后编译Linux内核,一定不要清理工程!
否则的话我们刚刚的设置就会被清理掉。编译完成往后利用新的zImage重启Linux,查看当前CPU的事情频率和调频策略。
我们学习的时候为了高性能,大家可以利用performance模式。但是在往后的实际产品开拓中,从省电的角度考虑,建议大家利用ondemand模式,一来可以省电,二来可以减少发热。
2、超频至700MHz
I.MX6ULL有多种型号,按照事情频率可以分为528MHz、700Mhz(实际696MHz),800MHz(实际792MHz)和900MHz(实际频率未知,该当在900MHz旁边)。个中900MHz的不支持RGB屏幕,以是正点原子Linux团队没有选择,而700MHz的没有工业级(事情温度-40~85°C以上),因此也没有选择700MHz的型号。末了就剩下了528MHz和800MHz的,目前正点原子只供应了528MHz的版本(型号为MCIMX6Y2CVM08AB),至于800MHz版本(型号为MCIMX6Y2CVM08AB)的核心板后续就看客户的需求,如果有需求就会加上,但是800MHz版本的I.MX6ULL芯片会贵一些,本钱会上涨。
虽然正点原子的I.MX6U-ALPHA开拓板所选择的I.MX6ULL标称最高只能事情在528MHz,但是其是可以超频的700MHz的(这里的700MHz实际上只有696MHz,但是NXP官方宣扬其为700MHz,以是我们就统一称为700MHz吧)。
声明:
对付想体验一下高性能的朋友体验一下超频,虽然笔者一贯在用700MHz来测试,而且正点原子的I.MX6U-ALPHA开拓板目前还没有涌现过超频不稳定的征象发生,但是!
毕竟是超频了的,肯定没有事情在528MHz稳定。
如果由于超频带来任何破坏,正点原子不负任何任务!
如果由于超频带来任何破坏,正点原子不负任何任务!
如果由于超频带来任何破坏,正点原子不负任何任务!
在实际的产品中,禁止任何超频!
务必严格按照I.MX6ULL手册上给出的标准事情频率来运行!
!
如果想要更高的性能,请购买相应型号的处理器!
看到这里,如果您还是执意要超频,那么就接着往下看,如果要放弃超频,那就跳过本小节,看下一小节。
超频设置实在很大略,修正一下设备树文件imx6ull.dtsi即可,打开imx6ull.dtsi,找到下面代码:
示例代码37.4.1.3 imx6ull.dtsi文件代码段
54 cpu0: cpu@0 {
55 compatible ="arm,cortex-a7";
56 device_type ="cpu";
57 reg =<0>;
58 clock-latency =<61036>;/ two CLK32 periods /
59 operating-points =<
60/ kHz uV /
619960001275000
627920001225000
635280001175000
643960001025000
65198000950000
66>;
67 fsl,soc-operating-points =<
68 / KHz uV /
69 9960001175000
70 7920001175000
71 5280001175000
72 3960001175000
73 1980001175000
74 >;
示例代码37.4.1.3便是设置CPU频率的,第61~65行和第69~73行便是I.MX6ULL所支持的频率,单位为KHz,可以看出I.MX6ULL(视详细型号而定)支持996MHz、792MHz、528MHz、396MHz和198MHz。在上一小节中,我们知道Linux内核默认支持198MHz、396MHz和528MHz,并不能支持到792MHz,解释MCIMX6Y2CVM05AB这颗芯片不能跑到792MHz。我们在示例代码37.4.2.1中加入针对696MHz的支持,修正往后代码如下:
示例代码37.4.1.4 增加696MHz的支持
54 cpu0: cpu@0 {
55 compatible ="arm,cortex-a7";
56 device_type ="cpu";
57 reg =<0>;
58 clock-latency =<61036>;/ two CLK32 periods /
59 operating-points =<
60/ kHz uV /
619960001275000
627920001225000
636960001225000
645280001175000
653960001025000
66198000950000
67>;
68 fsl,soc-operating-points =<
69 / KHz uV /
70 9960001175000
71 7920001175000
72 6960001175000
73 5280001175000
74 3960001175000
75 1980001175000
76 >;
第63行,加入了“696000 1225000”,这个便是696MHz的支持。
第72行,加入了“696000 1175000”,也是对696MHz的支持。
修恰好往后保存,并且编译设备树,在Linux内核源码根目录下输入如下命令编译设备树:
makedtbs
命令“makedtbs”只编译设备树文件,也便是将.dts编译为.dtb,编译完成往后利用新的设备树文件imx6ull-alientek_emmc.dtb启动Linux。重启往后查看文件/sys/devices/system/cpu/cpu0/cpufreq/ scaling_available_frequencies的内容,如图37.4.1.10所示:
图37.4.1.10文件scaling_available_frequencies内容
从图37.4.1.11可以看出,此时支持了696MHz。如果设置调频策略为performance,那么处理器就会一贯事情在696MHz。可以比拟一下事情在528MHz和696MHz下的BogoMIPS的值,528MHz主频下的BogoMIPS值如图37.4.1.12所示:
图37.4.1.12528MHz主频下的BogoMIPS
696MHz主频下的BogoMIPS值如图37.4.1.13所示:
图37.4.1.13696MHz主频下的BogoMIPS
从图37.4.1.12和图37.2.1.13中可以看到,528MHz和696MHz下的BogoMIPS值分别为8.00和10.54,相称于性能提升了(10.54/8)-1=31.75%。
37.4.2使能8线EMMC驱动正点原子EMMC版本核心板上的EMMC采取的8位数据线,事理图如图37.4.2.1所示:
图37.4.2.1 EMMC事理图
Linux内核驱动里面EMMC默认是4线模式的,4线模式肯定没有8线模式的速率快,以是本节我们将EMMC的驱动修正为8线模式。修正方法很大略,直接修正设备树即可,打开文件imx6ull-alientek-emmc.dts,找到如下所示内容:
示例代码37.4.2.1 imx6ull-alientek-emmc.dts代码段
734&usdhc2 {
735 pinctrl-names ="default";
736 pinctrl-0=<&pinctrl_usdhc2>;
737 non-removable;
738 status ="okay";
739};
关于设备树的事理以及内容我们后面会有专门的章节讲解,示例代码37.4.2.1中的代码含义我们现在不去纠结,只须要将其改为如下代码即可:
示例代码37.4.2.1 imx6ull-alientek-emmc.dts代码段
734&usdhc2 {
735 pinctrl-names ="default","state_100mhz","state_200mhz";
736 pinctrl-0=<&pinctrl_usdhc2_8bit>;
737 pinctrl-1=<&pinctrl_usdhc2_8bit_100mhz>;
738 pinctrl-2=<&pinctrl_usdhc2_8bit_200mhz>;
739 bus-width =<8>;
740 non-removable;
741 status ="okay";
742};
修正完成往后保存一下imx6ull-alientek-emmc.dts,然后利用命令“makedtbs”重新编译一下设备树,编译完成往后利用新的设备树重启Linux系统即可。
37.4.3 修正网络驱动由于在后面学习Linux驱动开拓的时候要用到网络调试驱动,以是必须要把网络驱动调试好。在讲解uboot移植的时候就已经说过了,正点原子开拓板的网络和NXP官方的网络硬件上不同,网络PHY芯片由KSZ8081换为了LAN8720A,两个网络PHY芯片的复位IO也不同。以是Linux内核自带的网络驱动是驱动不起来I.MX6U-ALPHA开拓板上的网络的,须要做修正。
1、修正LAN8720的复位引脚驱动
ENET1复位引脚ENET1_RST连接在I.M6ULL的SNVS_TAMPER7这个引脚上。ENET2的复位引脚ENET2_RST连接在I.MX6ULL的SNVS_TAMPER8上。打开设备树文件imx6ull-alientek-emmc.dts,找到如下代码:
示例代码37.4.3.1 imx6ull-alientek-emmc.dts代码段
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};
示例代码37.4.3.1中第588和589行便是初始化SNVS_TAMPER7和SNVS_TAMPER8这两个引脚的,不过看样子彷佛是作为了SPI4的IO,这不是我们想要的,以是将588和589这两行删除掉!
删除掉往后连续在imx6ull-alientek-emmc.dts中找到如下所示代码:
示例代码37.4.3.2 imx6ull-alientek-emmc.dts代码段
125 spi4 {
126 compatible ="spi-gpio";
127 pinctrl-names ="default";
128 pinctrl-0=<&pinctrl_spi4>;
129 pinctrl-assert-gpios =<&gpio5 8 GPIO_ACTIVE_LOW>;
......
133 cs-gpios =<&gpio5 70>;
第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的什么功能引脚,因此将示例代码37.4.3.2中的第129行和第133行处的代码删除掉!
!
否则会滋扰到网络复位引脚!
连续在imx6ull-alientek-emmc.dts中找到如下所示代码:
示例代码37.4.3.3 imx6ull-alientek-emmc.dts代码段
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>;
320};
321
322 pinctrl_enet2: enet2grp {
323 fsl,pins =<
324 MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
325 MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
326 MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
327 MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
328 MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
329 MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
330 MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
331 MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
332 MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
333 MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
334>;
335};
第309~320行,pinctrl_enet1是ENET1的IO初始化配置。
第322~335行,pinctrl_enet2是ENET2的IO初始化配置。
根据示例代码37.4.3.3,我们须要将ENET1的复位IO初始化配置添加到pinctrl_enet1中,将ENET2的复位IO初始化配置添加到pinctrl_enet2中,添加完成往后的代码如下所示:
示例代码37.4.3.4 imx6ull-alientek-emmc.dts代码段
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
...
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
...
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的配置代码。
修正完成往后记得保存一下imx6ull-alientek-emmc.dts,网络的复位引脚驱动就修恰好了。
2、修正LAN8720A的PHY地址
在uboot移植章节中,我们说过ENET1的LAN8720A地址为0x0,ENET2的LAN8720A地址为0x1。在imx6ull-alientek-emmc.dts中找到如下代码:
示例代码37.4.3.5 imx6ull-alientek-emmc.dts代码段
171&fec1 {
172 pinctrl-names ="default";
173 pinctrl-0=<&pinctrl_enet1>;
174 phy-mode ="rmii";
175 phy-handle =<ðphy0>;
176 status ="okay";
177};
178
179&fec2 {
180 pinctrl-names ="default";
181 pinctrl-0=<&pinctrl_enet2>;
182 phy-mode ="rmii";
183 phy-handle =<ðphy1>;
184 status ="okay";
185
186 mdio {
187 #address-cells =<1>;
188 #size-cells =<0>;
189
190 ethphy0: ethernet-phy@0 {
191 compatible ="ethernet-phy-ieee802.3-c22";
192 reg =<2>;
193};
194
195 ethphy1: ethernet-phy@1 {
196 compatible ="ethernet-phy-ieee802.3-c22";
197 reg =<1>;
198};
199};
200};
第171~177行,ENET1对应的设备树节点。
第179~200行,ENET2对应的设备树节点。但是第186~198行的mdio节点描述了ENET1和ENET2的PHY地址信息。将示例代码37.4.3.5改为如下内容:
示例代码37.4.3.6 imx6ull-alientek-emmc.dts代码段
171&fec1 {
172 pinctrl-names ="default";
173 pinctrl-0=<&pinctrl_enet1>;
174 phy-mode ="rmii";
175 phy-handle =<ðphy0>;
176 phy-reset-gpios =<&gpio5 7 GPIO_ACTIVE_LOW>;
177 phy-reset-duration =<26>;
178 status ="okay";
179};
180
181&fec2 {
182 pinctrl-names ="default";
183 pinctrl-0=<&pinctrl_enet2>;
184 phy-mode ="rmii";
185 phy-handle =<ðphy1>;
186 phy-reset-gpios =<&gpio5 8 GPIO_ACTIVE_LOW>;
187 phy-reset-duration =<26>;
188 status ="okay";
189
190 mdio {
191 #address-cells =<1>;
192 #size-cells =<0>;
193
194 ethphy0: ethernet-phy@0 {
195 compatible ="ethernet-phy-ieee802.3-c22";
196 smsc,disable-energy-detect;
197 reg =<0>;
198};
199
200 ethphy1: ethernet-phy@1 {
201 compatible ="ethernet-phy-ieee802.3-c22";
202 smsc,disable-energy-detect;
203 reg =<1>;
204};
205};
206};
第176和177行,添加了ENET1网络复位引脚所利用的IO为GPIO5_IO07,低电平有效。复位低电平旗子暗记持续韶光为26ms。
第186和187行,ENET2网络复位引脚所利用的IO为GPIO5_IO08,同样低电平有效,持续韶光同样为26ms。
第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。
至此,LAN8720A的PHY地址就改好了,保存一下imx6ull-alientek-emmc.dts文件。然后利用“makedtbs”命令重新编译一下设备树。
3、修正fec_main.c文件
要在I.MX6ULL上利用LAN8720A,须要修正一下Linux内核源码,打开drivers/net/ethernet/freescale/fec_main.c,找到函数fec_probe,在fec_probe中加入如下代码:
示例代码37.4.3.7 imx6ull-alientek-emmc.dts代码段
3438staticint
3439 fec_probe(struct platform_device pdev)
3440{
3441struct fec_enet_private fep;
3442struct fec_platform_data pdata;
3443struct net_device ndev;
3444int i, irq, ret =0;
3445struct resource r;
3446conststruct of_device_id of_id;
3447staticint dev_id;
3448struct device_node np = pdev->dev.of_node,phy_node;
3449int num_tx_qs;
3450int num_rx_qs;
3451
3452/ 设置MX6UL_PAD_ENET1_TX_CLK和MX6UL_PAD_ENET2_TX_CLK
3453 这两个IO的复用寄存器的SION位为1。
3454 /
3455void __iomem IMX6U_ENET1_TX_CLK;
3456void __iomem IMX6U_ENET2_TX_CLK;
3457
3458 IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC,4);
3459 writel(0X14, IMX6U_ENET1_TX_CLK);
3460
3461 IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC,4);
3462 writel(0X14, IMX6U_ENET2_TX_CLK);
3463
......
3656return ret;
3657}
第3455~3462便是新加入的代码,如果要在I.MX6ULL上利用LAN8720A就须要设置ENET1和ENET2的TX_CLK引脚复位寄存器的SION位为1。
4、配置Linux内核,使能LAN8720驱动
输入命令“makemenuconfig”,打开图形化配置界面,选择使能LAN8720A的驱动,路径如下:
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs
如图37.4.3.1所示:
图37.4.3.1 使能LAN8720A驱动
图37.4.3.1中选择将“Drivers for SMSC PHYs”编译到Linux内核中,因此“<>”里面变为了“”。LAN8720A是SMSC公司出品的,因此勾选这个往后就会编译LAN8720驱动,配置好往后退出配置界面,然后重新编译一下Linux内核。
5、修正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肯定也会利用到这个复位函数,此函数内容如下:
示例代码37.4.3.8 smsc_phy_reset函数
60staticint smsc_phy_reset(struct phy_device phydev)
61{
62 int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
63 if(rc <0)
64 return rc;
65
66 / If the SMSC PHY is in power down mode, then set it
67 in all capable mode before using it.
68 /
69 if((rc & MII_LAN83C185_MODE_MASK)== MII_LAN83C185_MODE_POWERDOWN){
70 int timeout =50000;
71
72 / set "all capable" mode and reset the phy /
73 rc |= MII_LAN83C185_MODE_ALL;
74 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
75 phy_write(phydev, MII_BMCR, BMCR_RESET);
76
77 / wait end of reset (max 500 ms) /
78 do{
79 udelay(10);
80 if(timeout--==0)
81 return-1;
82 rc = phy_read(phydev, MII_BMCR);
83 }while(rc & BMCR_RESET);
84 }
85 return0;
86}
第69行,只有PHY处于powerdown模式的时候第70~83行的代码段才会实行。
第75行,向LAN872A0的BMCR寄存器写入BMCR_RESET,也便是对LAN8720A进行软件初始化,以是smsc_phy_reset函数会对LAN8720A进行软件初始化。
看到没,只有LAN8720A处于powerdown模式的时候才会对LAN8720A进行软复位,但是我们在uboot中已经“唤醒”了LAN8720A,LAN8720A也已经事情了,因此它不可能处于powerdown模式,进而就没法对LAN8720A进行软复位。因此,我们要对smsc_phy_reset函数函数进行修正,将复位干系的代码早年提语句中提出来,不管LAN8720A有没有事情在powerdown模式下,只要调用smsc_phy_reset函数就对LAN8720A进行软复位,修正后的smsc_phy_reset函数内容如下:
示例代码37.4.3.9 修正后的smsc_phy_reset函数
60staticint smsc_phy_reset(struct phy_device phydev)
61{
62 int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
63 if(rc <0)
64 return rc;
65
66 / If the SMSC PHY is in power down mode, then set it
67 in all capable mode before using it.
68 /
69 if((rc & MII_LAN83C185_MODE_MASK)== MII_LAN83C185_MODE_POWERDOWN){
70
71 / set "all capable" mode and reset the phy /
72 rc |= MII_LAN83C185_MODE_ALL;
73 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
74 }
75
76 phy_write(phydev, MII_BMCR, BMCR_RESET);
77 / wait end of reset (max 500 ms) /
78 int timeout =50000;
79 do{
80 udelay(10);
81 if(timeout--==0)
82 return-1;
83 rc = phy_read(phydev, MII_BMCR);
84 }while(rc & BMCR_RESET);
85
86 return0;
87}
重点是76~84行,我们将软复位代码移出来,这样每次调用smsc_phy_reset函数LAN8720A都会被软复位。修正往后基本上每次通过NFS挂载根文件系统都会成功。
6、网络驱动测试
修恰好设备树和Linux内核往后重新编译一下,得到新的zImage镜像文件和imx6ull-alientek-emmc.dtb设备树文件,利用网线将I.MX6U-ALPHA开拓板的两个网口与路由器或者电脑连接起来,末了利用新的文件启动Linux内核。启动往后利用“ifconfig”命令查看一下当前活动的网卡有哪些,结果如图37.4.3.2所示:
图37.4.3.2 ifconfig命令结果
从图37.4.3.2可以看出,当前没有活动的网卡。输入命令“ifconfig-a”来查看一下开拓板中存在的所有网卡,结果如图37.4.3.3所示:
图37.4.3.3 开拓板所有网卡
图37.4.3.3中can0和can1为CAN接口的网卡,eth0和eth1才是网络接口的网卡,个中eth0对应于ENET1,eth1对应于ENET2。利用如下命令依次打开eth0和eth1这两个网卡:
ifconfig eth0 up
ifconfig eth1 up
网卡的打开过程如图37.4.3.4所示:
图37.4.3.4 两个网卡打开过程
从图37.4.3.4中可以看到“SMSC LAN8710/LAN8720”字样,解释当前的网络驱动利用的便是我们前面使能的SMSC驱动。
再次输入“ifconfig”命令来查看一下当前活动的网卡,结果如图37.4.3.5所示:
图37.4.3.5 当前活动的网卡。
可以看出,此时eth0和eth1两个网卡都已经打开,并且事情正常,但是这两个网卡都还没有IP地址,以是不能进行ping等操作。利用如下命令给两个网卡配置IP地址:
ifconfig eth0 192.168.1.251
ifconfig eth1 192.168.1.252
上述命令配置eth0和eth1这两个网卡的IP地址分别为192.168.1.251和192.168.1.252,把稳IP地址选择的合理性,一定要和自己的电脑处于同一个网段内,并且没有被其他的设备占用!
设置好往后,利用“ping”命令来ping一下自己的主机,如果能ping通那解释网络驱动修正成功!
比如我的Ubuntu主机IP地址为192.168.1.250,利用如下命令ping一下:
ping 192.168.1.250
结果如图37.4.3.6所示:
图37.4.3.6 ping结果
可以看出,ping成功,解释网络驱动修正成功!
我们在后面的构建根文件系统和Linux驱动开拓中就可以利用网络调试代码啦,好嗨森!
在修正网络驱动的时候我们通过图形界面使能了LAN8720A的驱动,使能往后会在.config中存在如下代码:
CONFIG_SMSC_PHY=y
打开drivers/net/phy/Makefile,有如下代码:
示例代码37.4.4.1 drivers/net/phy/Makefile代码段
11 obj-$(CONFIG_SMSC_PHY)+= smsc.o
当CONFIG_SMSC_PHY=y的时候就会编译smsc.c这个文件,smsc.c便是LAN8720A的驱动文件。但是当我们实行“makeclean”清理工程往后.config文件就会被删除掉,因此我们所有的配置内容都会丢失,结果便是半途而废,一“删”回到解放前!
以是我们在配置完图形界面往后经由测试没有问题,就必须要保存一下配置文件。保存配置的方法有两个。
1、直接另存为.config文件
既然图形化界面配置后的配置项保存在.config中,那么就大略粗暴,直接将.config文件另存为imx_alientek_emmc_defconfig,然后其复制到arch/arm/configs目录下,更换以前的imx_alientek_emmc_defconfig。这样往后实行“makeimx_alientek_emmc_defconfig”重新配置Linux内核的时候就会利用新的配置文件,默认就会使能LAN8720A的驱动。
2、通过图形界面保存配置文件
比较于第1种直接另存为.config文件,第2种方法就很“文雅”了,在图形界面中保存配置文件,在图形界面中会有“< Save >”选项,如图37.4.4.1所示:
图37.4.4.1 保存配置
通过键盘的“→”键,移动到“< Save >”选项,然后按下回车键,打开文件名输入对话框,如图37.4.4.2所示:
图37.4.4.2 输入文件名
在图37.4.4.2中输入要保存的文件名,可以带路径,一样平常是相对路径(相对付Linux内核源码根目录)。比如我们要将新的配置文件保存到目录arch/arm/configs下,文件名为imx_alientek_emmc_defconfig,也便是用新的配置文件更换掉老的默认配置文件。那么我们在图37.4.4.2中输入“arch/arm/configs/imx_alientek_emmc_defconfig”即可,如图37.4.4.3所示:
图37.4.4.3 输入文件名
设置好文件名往后选择下方的“< Ok >”按钮,保存文件并退出。退出往后再打开imx_alientek_emmc_defconfig文件,就会在此文件中找到“CONFIG_SMSC_PHY=y”这一行,如图37.4.4.4所示:
图37.4.4.4 新的配置文件
同样的,利用“makeimx_alientek_emmc_defconfig”重新配置Linux内核的时候,LAN8720A的驱动就会使能,并被编译进Linux镜像文件zImage中。
关于Linux内核的移植就讲解到这里,大略总结一下移植步骤:
①、在Linux内核中查找可以参考的板子,一样平常都是半导体厂商自己做的开拓板。
②、编译出参考板子对应的zImage和.dtb文件。
③、利用参考板子的zImage文件和.dtb文件在我们所利用的板子上启动Linux内核,看能否启动。
④、如果能启动的话就万事大吉,如果不能启动那就悲剧了,须要调试Linux内核。不过一样平常都会参考半导体官方的开拓板设计自己的硬件,以是大部分情形下都会启动起来。启动Linux内核用到的外设不多,一样平常就DRAM(Uboot都初始化好的)和串口。作为终端利用的串口一样平常都会参考半导体厂商的Demo板。
⑤、修正相应的驱动,像NAND Flash、EMMC、SD卡等驱动官方的Linux内核都是已经供应好了,基本不会出问题。重点是网络驱动,由于Linux驱动开拓一样平常都要通过网络调试代码,以是一定要确保网络驱动事情正常。如果是处理器内部MAC+外部PHY这种网络方案的话,一样平常网络驱动都很好处理,由于在Linux内核中是有外部PHY通用驱动的。只要设置好复位引脚、PHY地址信息基本上都可以驱动起来。
⑥、Linux内核启动往后须要根文件系统,如果没有根文件系统的话肯定会崩溃,以是确定Linux内核移植成功往后就要开始根文件系统的构建。