Linux系统移植:原厂 Kernel 移植到开发板
Posted 嵌入式up笔记
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 中调频策略
- Performance,最高性能,直接用最高频率,不考虑耗电
- Interactive,一开始直接用最高频率,然后根据 CPU 负载慢慢降低
- Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个
- Userspace,可以在用户空间手动调节频率
- 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)