请确保以完成 bootloader 的移植:U-boot 配置、编译、移植
一、源码下载
1. Linux 官网下载:The Linux Kernel Archives
2.半导体厂商官网下载: 面向i.MX 6ULL和6ULZ应用处理器的评估套件
我用的是 NXP 提供的 linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2
二、配置文件
下载到虚拟机后,解压进入目录
修改Makefile
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
保存后退出
拷贝一份配置。
cd arch/arm/configs/
cp imx_v7_mfg_defconfig imx_lyh_emmc_defconfig
三、设备树
cd arch/arm/boot/dts
cp imx6ull-14x14-evk.dts imx6ull-lyh-emmc.dts
修改当前目录的 Makefile,添加自己的 dtb
四、编译
注意:我使用的交叉编译是 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf ,在测试其他交叉编译版本时,发现可能编译失败,建议使用与笔者相同的版本
写一个简单的脚本,方便编译:
vi imx_lyh.sh
#!/bin/sh
make distclean
make imx_lyh_emmc_defconfig
make menuconfig
make all -j6
chmod 777 imx_lyh.sh./imx_lyh.sh
tftp 80800000 zImage //zImage 下载到开发板 DRAM 的 0x80800000tftp 83000000 imx6ull-lyh-emmc.dtbbootz 80800000 - 83000000
出现以下界面:
五、修改CPU 主频和网络驱动
setenv bootargs "console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.137.10:/home/lyh/linux/nfs/rootfs ip=192.168.137.9:192.168.137.10:192.168.137.1:255.255.255.0::eth0:off"
emmc启动
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
5.1 CPU主频
cat /proc/cpuinfo
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 在各频率下的运行时间以及变频次数。
通过更改 scaling_governor 去更改频率
5.2 修改 EMMC 驱动
打开设备树文件 imx6ull-alientek-emmc.dts ,找到 &usdhc2
改为:
5.3 修改网络驱动
还是设备树文件 imx6ull-alientek-emmc.dts 中,找到:MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 ,删掉这两行
再找到 &gpio5 8 ,删掉图示两行
/*enet1 reset*/pinctrl_enet1_reset : enet1resetgrp {fsl , pins = </* used for enet1 reset */MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0>;};/*enet2 reset */pinctrl_enet2_reset : enet2resetgrp {fsl , pins = </* used for enet2 reset */MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0>;};
MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b009
pinctrl - 0 = <& pinctrl_enet1& pinctrl_enet1_reset >;pinctrl - 0 = <& pinctrl_enet2& pinctrl_enet2_reset >;
添加引脚信息
phy - reset - gpios = <& gpio5 7 GPIO_ACTIVE_LOW >;phy - reset - duration = < 200 >;phy - reset - gpios = <& gpio5 8 GPIO_ACTIVE_LOW >;phy - reset - duration = < 200 >;
继续修改下方内容
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>;
};
到此,设备树文件修改完成,保存退出
接下来修改 drivers/net/ethernet/freescale/fec_main.c 文件,找到 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 );
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;
}
运行编译脚本,在 menuconfig 里配置驱动
记得保存配置,以免每次编译都要配置。