Linux系统移植:原厂 Kernel 移植到开发板

Posted Top嵌入式

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux系统移植:原厂 Kernel 移植到开发板相关的知识,希望对你有一定的参考价值。

文章目录

Linux系统移植:原厂 Kernel 移植到开发板

一、获取原厂内核并编译

我直接拿原子提供的源码编译,编译指令

#!/bin/sh
make 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

编译完获得镜像文件:

设备树文件:

二、内核启动测试

从板子上通过网络来启动编译好的 linux 内核,看看现象,要想网络互相 ping 通,必须要在局域网下!

设置板子 uboot 的 bootargs 参数为 console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw

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

然后将生成的镜像文件和设备树拷贝到 FTP 根目录,用于从网络启动:

cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb ~/linux/tftp/
cp arch/arm/boot/zImage ~/linux/tftp/

在开发板输入

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

进行网络启动,系统启动成功,可以输入命令:

我们刚刚启动的根文件系统由 uboot 的 bootargs 环境变量进行指引,其中 root=/dev/mmcblk1p2 就是指引了根文件系统的参数存放在EMMC 的分区 2 中,没有跟文件系统的话就会启动不成功,根文件系统缺失会导致的内核崩溃

三、添加自己板子文件

添加针对正点原子阿尔法开发板的配置文件

3.1 板子配置文件

将 arch/arm/configs 下的 imx_v7_mfg_defconfig 配置文件复制一份, 命名为我们自己配置文件的名称imx_my_emmc_defconfig,以后就在里面修改配置我们自己的内核

cp arch/arm/configs/imx_v7_mfg_defconfig arch/arm/configs/imx_my_emmc_defconfig

然后就可以使用

make imx_my_emmc_defconfig

配置 Linux 内核了

3.2 板子设备树

从目录 arch/arm/boot/dts 中复制一份 imx6ull-14x14-evk.dts,重命名为 imx6ull-my-emmc.dts 作为我们自己板子的设备树,以后就在里面修改

cp arch/arm/boot/dts/imx6ull-14x14-evk.dts arch/arm/boot/dts/imx6ull-my-emmc.dts

然后在 arch/arm/boot/dts/Makefile,找到 “dtb-$(CONFIG_SOC_IMX6ULL)” 配置项,在此配置项中加入 “imx6ull-my-emmc.dtb” 将我们的设备树追加进去,dts 编译会生成 dtb

3.3 编译

修改之前的编译脚本

#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_my_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

赋予脚本执行权限,然后执行,编译完成入如下,编译成功上面内核配置没问题

复制 zImage 和设备树 .dtb 文件到 tftp 目录下,使用网络启动,加载我们自己的设备树:

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

启动成功:

四、重要配置修改

4.1 主频修改

在启动系统上打印 CPU 主频,运行频率信息存放在 /sys/bus/cpu/devices/cpu0/cpufreq 中

文件含义如下:

  • 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 中调频策略
  1. Performance,最高性能,直接用最高频率,不考虑耗电
  2. Interactive,一开始直接用最高频率,然后根据 CPU 负载慢慢降低
  3. Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个
  4. Userspace,可以在用户空间手动调节频率
  5. Ondemand,定时检查负载,然后根据负载来调节频率。负载低的时候降低 CPU 频率
  • scaling_max_freq:governor(调频)可以调节的最高频率
  • cpuinfo_min_freq:governor(调频)可以调节的最低频率

打印当前频率:792M

CPU 可支持的切换频率有 4 种:

我们修改工作频率,在配置文件中将默认工作模式改为 Powersave 模式

sudo vim arch/arm/configs/imx_my_emmc_defconfig

添加默认代码

修改后重新编译,从网络启动系统内核,然后查看系统运行频率,变成 198M 了

修改工作频率的方法除了修改 defconfig 文件,还可以通过图形化配置,使用

make menuconfig

图形化配置后再生成配置文件,然后编译,两种方法结果都一样

一般使用 ondemand 模式,一可省电,二可减少发热

除了以上的工作频率,我们也可以运行自己想要的程序,具体修改就不多说了,一般使用原厂提供的就行

4.2 EMMC驱动修改

Linux 内核驱动里面 EMMC 默认是 4 线模式的,没有 8 线模式的速度快,所以我们将 EMMC 的驱动修改为 8 线

修改 EMMC 接线直接修改设备树就行,打开文件 imx6ull-alientek-emmc.dts,将下面的配置文件

修改为

然后单独编译 dts 到 dtb:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

重新启动系统

4.3 网络驱动修改

原子开发板的网络和 NXP 官方的网络硬件上不同,网络 PHY 芯片由 KSZ8081 换为了 LAN8720A,Linux 内核自带的网络驱动无法驱动,需要做修改

4.3.1 修改芯片复位引脚

打开设备树文件 imx6ull-my-emmc.dts 找到下面的代码,删除多余 IO 口配置

修改后:

删除如下代码, 让 GPIO5_IO07 和 GPIO5_IO08 分别作为 ENET1 和 ENET2 的复位引脚

然后找到 iomuxc_snvs,将刚刚删除的两个引脚作为复位引脚配置,代码如下:

4.3.2 网络时钟引脚配置

在 imx6ull-my-emmc.dts ,将如下两个代码

后面的参数修改为 0x4001b009(两个引脚的电气属性值)

4.3.3 修改节点的 pinctrl-0 属性

修改位置如下

将这两个节点属性修改为下图,传入我们上面写的复位函数:

4.3.4 修改网口节点以及添加复位

设备树文件中,在 fec2 的节点有写网口的地址信息

修改 reg 的值,对应 0 和 1,因为 ethernet-phy@ 后面的数字是 PHY 的地址,而 ENET1 的 PHY 地址为 0,
所以 @ 后面是 0,ENET2 同理:

在两个 fec 节点内添加复位引脚,并设置持续时间 200ms,用于后面的软件复位使用

在节点中添加驱动信息,指引内核找到对应的驱动程序

配置完成后,重新编译设备树

4.3.5 修改网络驱动

打 开 drivers/net/ethernet/freescale/fec_main.c 文件,在函数 fec_probe 中加入如下代码:

用于复位两个芯片,保证正常工作,输入下面代码,打开图形化界面

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  menuconfig

在界面使能网口驱动,路径如下

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

勾选后就会编译 LAN8720 驱动

4.3.6 修改 smsc.c 文件,添加软复位

在 Linux 中需要对 LAN8720A 进行一次软复位,保证正常工作,LAN8720A 的驱动文件是drivers/net/phy/smsc.c,修改该文件即可,找到里面的 smsc_phy_reset 复位函数

修改为下面的代码

	//初始化变量
	int err, phy_reset;
	int msec = 1;
	struct device_node *np;
	int timeout = 50000;
	//获取 FEC1 网卡对应的设备节点
	if(phydev->addr == 0) /* FEC1 */ 
	
		np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000");
		if(np == NULL)
		
			return -EINVAL;
		
	
	//获取 FEC2 网卡对应的设备节点
	if(phydev->addr == 1) /* FEC2 */ 
	
		np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000");
		if(np == NULL)
		
			return -EINVAL;
		
	
	//从设备树中获取“phy-reset-duration”属性信息,也就是复位时间
	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-gpios”属性信息,也就是复位 IO
	phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
	if (!gpio_is_valid(phy_reset))
		return;
	//复位 LAN8720A
	gpio_direction_output(phy_reset, 0);
	gpio_set_value(phy_reset, 0);
	msleep(msec);
	gpio_set_value(phy_reset, 1);
	//处于 Powerdown 模式的时候才会软复位 LAN8720
	int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
	if (rc < 0)
		return rc;
	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;

修改好设备树和 Linux 内核以后重新编译一下,启动 Linux 内核,使用 ifconfig 命令查看网卡

ping 一下主机,成功

4.4 保存修改后配置文件

修改网络驱动的时候我们通过图形界面使能了 LAN8720A 的驱动,使能后会在.config 中存在如下代码

CONFIG_SMSC_PHY=y

当 CONFIG_SMSC_PHY=y 的时候就会编译 smsc.c 这个驱动文件,当我们执行 make clean 清理工程以后.config 文件就会被删除掉,所以要保存该文件

  • 非图形化

非图形化下,将生成的 .config 文件直接改名 imx_my_emmc_defconfig 配置文件,保存到 arch/arm/configs下

  • 图形化

在图形化界面将生成的 .config 文件改名 imx_my_emmc_defconfig 配置文件,保存到 arch/arm/configs 下

五、移植总结

  • 搞到原厂kernel源码
  • 复制配置文件、设备树文件,编译下载测试一下linux能不能启动
  • 修改配置文件
  • 修改设备树文件(网口、EMMC、串口等重要的设备树和驱动文件,适配自己的板子)
  • 编译生成针对开发板的的 zImage 和设备树文件
  • 移植 rootfs
  • 完结撒花

以上是关于Linux系统移植:原厂 Kernel 移植到开发板的主要内容,如果未能解决你的问题,请参考以下文章

全志H3系统移植 | 移植主线最新uboot 2023.04和kernel 6.1.11到Nanopi NEO开发板

嵌入式 Linux开发Kernel移植——kernel内核简介

RK3399系统移植 | 基于rk-linux-sdk移植kernel(4.4.194)

RK3399系统移植 | 基于rk-linux-sdk移植kernel(4.4.194)

安卓rom移植到底是啥意思?

Linux系统移植:Kernel 顶层 Makefile(下)