imx6ull-系统移植篇21——Linux 内核移植(下)

发布于:2025-07-25 ⋅ 阅读:(21) ⋅ 点赞:(0)

目录

前言

CPU 主频修改

查看CPU频率

CPU调频策略

查看CPU各频率工作时间

配置CPU频率

修改 EMMC 驱动

使能 8 线 EMMC 驱动

关闭 EMMC 1.8V 供电选项

网络驱动修改

修改引脚

修改pinctrl-0 属性

修改PHY 地址

修改 fec_main.c 文件

网络驱动测试


前言

在上一讲实验里,Linux 内核移植(上),我们先将NXP官方的linux编译了一下,熟悉linux的编译流程;又在linux中添加自己的开发板,也就是正点原子的 I.MX6U-ALPHA 开发板。

本讲实验继续未完成的linux移植工作,也就是对CPU 主频和网络驱动进行修改

CPU 主频修改

正点原子 I.MX6U-ALPHA 开发板所使用的 I.MX6ULL 芯片主频都是 792MHz 的。

我们需要设置 I.MX6U-ALPHA 开发板工作在 792MHz。

查看CPU频率

首先,确保 EMMC 中的根文件系统可用!然后重新启动开发板,进入终端(可以输入命令),如图:

输入cat 命令查看 cpu 信息:

可以看出:BogoMIPS 为 3.00, BogoMIPS 是 Linux 系统中衡量处理器运行速度的一个“尺子”,处理器性能越强,主频越高, BogoMIPS 值就越大。

BogoMIPS 只是粗略的计算 CPU 性能,但不能直接看出CPU的频率。

所以进入到目录/sys/bus/cpu/devices/cpu0/cpufreq 中,此目录下会有很多文件,如图:

此目录中记录了 CPU 频率等信息,这些文件的含义如下:

​文件/参数​

​描述​

​单位​

cpuinfo_cur_freq

当前 CPU 工作频率(直接从 CPU 寄存器读取)

KHz

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 频率(不直接读取硬件寄存器)

KHz

scaling_driver

当前 CPU 使用的调频驱动

scaling_governor

当前正在使用的调频策略(如 performancepowersaveondemand等)

scaling_max_freq

当前调频策略(governor)可以调节的最高频率(可能低于 cpuinfo_max_freq

KHz

scaling_min_freq

当前调频策略(governor)可以调节的最低频率(可能高于 cpuinfo_min_freq

KHz

    如果需要查询或修改这些值,可以使用以下命令:

    cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor  # 查看当前调频策略
    echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor  # 设置为性能模式

    将上面所提到的值都看一遍,如下:

    # 当前CPU实际运行频率(直接从硬件寄存器读取)
    cpuinfo_cur_freq = 198000  # 当前运行在198MHz(最低频率)
    
    # CPU硬件支持的最大/最小频率范围
    cpuinfo_max_freq = 792000  # 硬件支持的最高频率792MHz
    cpuinfo_min_freq = 198000  # 硬件支持的最低频率198MHz
    
    # cpufreq子系统当前使用的频率值
    scaling_cur_freq = 198000  # 内核记录的当前频率198MHz(与cpuinfo_cur_freq一致)
    
    # 当前调频策略允许的范围
    scaling_max_freq = 792000  # 调频策略允许设置的最高频率(与硬件上限一致)
    scaling_min_freq = 198000  # 调频策略允许设置的最低频率(与硬件下限一致)
    
    # 该CPU支持的所有可用频率档位
    scaling_available_frequencies = 198000 396000 528000 792000  
    # 可用频率档位:198MHz, 396MHz, 528MHz, 792MHz(共4档)
    
    # 当前使用的调频策略
    scaling_governor = ondemand  
    # 使用"按需调节"策略:
    # - 当系统负载升高时自动提升频率
    # - 空闲时自动降频到最低档
    # - 在性能与功耗间取得平衡

    CPU调频策略

    Linux 内核一共有 5 种调频策略:

    • Performance,最高性能,直接用最高频率,不考虑耗电。
    • Interactive,一开始直接用最高频率,然后根据 CPU 负载慢慢降低。
    • Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个!
    • Userspace,可以在用户空间手动调节频率。
    • Ondemand,定时检查负载,然后根据负载来调节频率。负载低的时候降低 CPU 频率,这样省电,负载高的时候提高 CPU 频率,增加性能。

    查看CPU各频率工作时间

    查看 stats 目录下的 time_in_state 文件可以看到 CPU 在各频率下的工作时间,命令如下:

    cat /sys/bus/cpu/devices/cpu0/cpufreq/stats/time_in_state

    结果如图:

    可以看出, CPU 在 198MHz、 396MHz、 528MHz 和 792MHz 都工作过,其中 198MHz 的工作时间最长。

    当前我们开发板并没有做什么工作,因此 CPU 频率降低为 198MHz 以省电。

    配置CPU频率

    假如我们想让 CPU 一直工作在 792MHz,可以:

    • 配置 Linux 内核,将调频策略选择为 performance。
    • 或者修改 imx_alientek_emmc_defconfig 文件。

    imx_alientek_emmc_defconfig文件中有下面几行:

    # 默认的频率调节策略配置为ondemand(按需调节)
    CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y  
    # 说明:内核启动时默认使用ondemand策略,该策略会根据CPU负载动态调整频率,负载高时升频,空闲时降频,平衡性能和功耗
    
    # 启用powersave(节能)策略
    CONFIG_CPU_FREQ_GOV_POWERSAVE=y  
    # 说明:该策略会始终让CPU运行在最低频率,最大化节省功耗,适用于对性能要求不高的场景
    
    # 启用userspace(用户空间)策略
    CONFIG_CPU_FREQ_GOV_USERSPACE=y  
    # 说明:允许用户空间程序通过/sys接口直接设置CPU频率,需要配合cpufreqd等守护进程使用
    
    # 启用interactive(交互式)策略
    CONFIG_CPU_FREQ_GOV_INTERACTIVE=y  
    # 说明:针对交互式设备(如手机/平板)优化的策略,比ondemand更激进,能更快响应突发负载, 但功耗也相对较高

    将这几行代码,修改为如下:

    #CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
    CONFIG_CPU_FREQ_GOV_POWERSAVE=y
    CONFIG_CPU_FREQ_GOV_USERSPACE=y
    CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
    CONFIG_CPU_FREQ_GOV_ONDEMAND=y

    修改完成以后重新编译 Linux 内核,编译之前先清理一下工程。因为我们重新修改过默认配 置文 件了, 编译完成以后使用新的 zImage 镜像文件重新启动 Linux。

    再次查看/sys/devices/system/cpu/cpu0/cpufreq/ cpuinfo_cur_freq 文件的值,如图:

    可以看出,当前 CPU 频率为 792MHz 了。

    查看 scaling_governor 文件看一下当前的调频策略,如图:

    可以看出当前的 CPU 调频策略为 preformance,也就是高性能模式,一直以最高主频运行。

    通过图形化界面配置 Linux 内核的 CPU 调频策略,输入“ make menuconfig”打开 Linux 内核的图形化配置界面,如图:

    进入如下路径:

    CPU Power Management -> CPU Frequency scaling -> Default CPUFreq governor

    打开默认调频策略选择界面,选择“performance”,如图:

    选择以后退出图形化配置界面,然后编译 Linux内核,记得不要清理工程,否则的话我们刚刚的设置就会被清理掉。

    编译完成以后使用新的zImage 重启 Linux,查看当前 CPU 的工作频率和调频策略。

    另外,在实际开发中,建议大家使用 ondemand 模式,一来可以省电,二来可以减少发热。

    修改 EMMC 驱动

    使能 8 线 EMMC 驱动

    正点原子 EMMC 版本核心板上的 EMMC 采用的 8 位数据线,原理图如下:

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

    修改方法很简单,直接修改设备树即可,打开文件 imx6ull-alientek-emmc.dts,找到如下所示内容:

    &usdhc2 {                          // 引用usdhc2节点(在芯片的dtsi中已定义)
        pinctrl-names = "default";     // 指定引脚控制状态名称(默认状态)
        pinctrl-0 = <&pinctrl_usdhc2>; // 关联具体的引脚配置组(由pinctrl_usdhc2定义)
        non-removable;                 // 标记设备不可热插拔(如eMMC芯片)
        status = "okay";               // 启用该控制器
    };

    将这一段代码修改为:

    &usdhc2 {
        pinctrl-names = "default", "state_100mhz", "state_200mhz";  // 定义3种引脚状态
        pinctrl-0 = <&pinctrl_usdhc2_8bit>;        // 默认频率引脚配置
        pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>; // 100MHz模式引脚配置
        pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>; // 200MHz模式引脚配置
        bus-width = <8>;                           // 8位数据总线(eMMC典型配置)
        non-removable;                             // 设备不可热插拔(eMMC特性)
        status = "okay";                           // 启用控制器
    };

    关闭 EMMC 1.8V 供电选项

    由原理图可以看出,此时 EMMC 工作电压是 3.3V 的。

    因此我们还需要在usdhc2 节点内容中,关闭 1.8V 这个功能选项。 防止内核在运行的时候用 1.8V 去驱动 EMMC,导致 EMMC 驱动出现问题。

    修改后的 usdhc2 节点内容如下:

    &usdhc2 {
        pinctrl-names = "default", "state_100mhz", "state_200mhz";  // 多频率状态支持
        pinctrl-0 = <&pinctrl_usdhc2_8bit>;        // 默认模式引脚配置(通常50MHz)
        pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>; // 100MHz高速模式
        pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>; // 200MHz超高速模式
        bus-width = <8>;                           // 8位数据总线(eMMC标准)
        non-removable;                             // 非热插拔设备(eMMC特性)
        no-1-8-v;                                  // 禁用1.8V低电压模式
        status = "okay";                           // 启用控制器
    };

    修改完成以后保存一下 imx6ull-alientek-emmc.dts,然后使用命令“make dtbs”重新编译一下设备树,编译完成以后使用新的设备树重启 Linux 系统即可。

    网络驱动修改

    在讲解 uboot 移植的时候,U-Boot 移植(下),我们已经知道,正点原子开发板的网络和 NXP 官方的网络硬件上不同:

    • 网络 PHY 芯片由 KSZ8081 换为了 SR8201F,
    • 两个网络 PHY 芯片的复位 IO 也不同。

    所以 Linux 内核自带的网络驱动是驱动不起来 I.MX6U-ALPHA 开发板上的网络的,需要做修改。

    修改引脚

    ENET1 复位引脚 ENET1_RST 连接在 I.M6ULL 的 SNVS_TAMPER7 这个引脚上。

    ENET2的复位引脚 ENET2_RST 连接在 I.MX6ULL 的 SNVS_TAMPER8 上。

    打开设备树文件 imx6ull-alientek-emmc.dts,找到如下代码:

    将红框中的初始化 SNVS_TAMPER7 和 SNVS_TAMPER8 这两个引脚的代码删除掉。

    继续在 imx6ull-alientek-emmc.dts 中找到如下所示代码:

    现在我们需要 GPIO5_IO07 和 GPIO5_IO08 分别作为 ENET1 和 ENET2 的复位引脚,而不是 SPI4 的什么功能引脚,所以将红框中的2行代码删除掉,防止干扰到网络复位引脚。

    继续在 imx6ull-alientek-emmc.dts 中找到名为“iomuxc_snvs”的节点:

    仿照格式在该节点内末尾处,添加网络复位引脚信息:

    		/*enet1 reset zuozhongkai*/
    		pinctrl_enet1_reset: enet1resetgrp {
    			fsl,pins = <
    				/* used for enet1 reset */
    				MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
    			>;
    		};
    
    		/*enet2 reset zuozhongkai*/
    		pinctrl_enet2_reset: enet2resetgrp {
    			fsl,pins = <
    				/* used for enet2 reset */
    				MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
    			>;
    		};

    继续在 imx6ull-alientekemmc.dts 中找到如下所示代码:

    红框中的2行代码,分别为 ENET1 和 ENET2 的网络时钟引脚配置信息,将这两个引脚的电气属性值改为 0x4001b031(原来默认值就是 0x4001b031)。

    修改完成以后记得保存一下 imx6ull-alientek-emmc.dts,网络复位以及时钟引脚驱动就修改好了。

    修改pinctrl-0 属性

    在 imx6ull-alientek-emmc.dts 文件中找到名为“fec1”和“fec2”的这两个节点,修改其中的“pinctrl-0”属性值,修改以后如下所示:

    修改PHY 地址

    我们说过:

    • ENET1 的 LAN8720A 地址为 0x2,
    • ENET2 的 LAN8720A地址为 0x1。

    在 imx6ull-alientek-emmc.dts 中找到如下代码:

    像上图一样,添加上这两行代码:

    phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
    phy-reset-duration = <200>;

    同理,在fec2节点中,添加如下代码:

    	phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
    	phy-reset-duration = <200>;

    另外,继续添加代码:

    smsc,disable-energy-detect

    最后这段代码如下图:

    ENET1 网络复位引脚所使用的 IO 为 GPIO5_IO07,低电平有效。复位低电平信号持续时间为 200ms。

    ENET2 网络复位引脚所使用的 IO 为 GPIO5_IO08,同样低电平有效,持续时间同样为 200ms。

    “smsc,disable-energy-detect”表明 PHY 芯片是 SMSC 公司的,这样 Linux内核就会找到 SMSC 公司的 PHY 芯片驱动来驱动 LAN8720A。

    注意“ethernet-phy@”后面的数字是 PHY 的地址, ENET1 的 PHY 地址为 2,ENET2 的 PHY 地址为 1.

    修改 fec_main.c 文件

    要在 I.MX6ULL 上使用SR8201F , 需要修改一下 Linux 内核源码 。

    打开drivers/net/ethernet/freescale/fec_main.c,找到函数 fec_reset_phy,在 fec_reset_phy 函数中加入如下代码:

    根据 SR8201F 收据手册上的要求, SR8201F 在复位结束以后需要等待至少 150ms 才能操作 SR8201F,因此这里添加了一个 200ms 的延时。

    网络驱动测试

    修改好设备树和 Linux 内核以后重新编译一下,得到新的 zImage 镜像文件和 imx6ullalientek-emmc.dtb 设备树文件:

    cd arch/arm/boot/dts进入这个路径下,找到dts文件:

    使用网线将 I.MX6U-ALPHA 开发板的两个网口与路由器或者电脑连接起来,最后使用新的文件启动 Linux 内核。

    tftp 80800000 zImage
    tftp 83000000 imx6ull-alientek-emmc.dtb
    bootz 80800000 – 83000000

    启动以后,输入命令“ifconfig -a”来查看一下开发板中存在的所有网卡,结果如图:

    eth0 和 eth1 是网络接口的网卡,其中 eth0 对应于 ENET2, eth1 对应于 ENET1。

    使用如下命令依次打开 eth0 和 eth1 这两个网卡:

    ifconfig eth0 up
    ifconfig eth1 up

    网卡的打开过程如图:

    可以看到“Generic PHY”字样,说明当前的网络驱动使用的就是 Linux 内核自带的通用网络 PHY 驱动。

    再次输入“ifconfig”命令来查看一下当前活动的网卡,结果如图:

    可以看出,此时 eth0 和 eth1 两个网卡都已经打开,并且工作正常,但是这两个网卡都还没有 IP 地址,所以不能进行 ping 等操作。

    使用如下命令给两个网卡配置 IP 地址:

    ifconfig eth0 192.168.1.251
    ifconfig eth1 192.168.1.252

    设置好以后,使用“ping”命令来 ping 一下自己的主机,如果能 ping 通那说明网络驱动修改成功:

    我们在后面的构建根文件系统和 Linux 驱动开发中就可以使用网络调试代码。

    关于 Linux 内核的移植,简单总结一下移植步骤:

    1. 在 Linux 内核中查找可以参考的板子,一般都是半导体厂商自己做的开发板。
    2. 编译出参考板子对应的 zImage 和.dtb 文件。
    3. 使用参考板子的 zImage 文件和.dtb 文件在我们所使用的板子上启动 Linux 内核,看能否启动。
    4. 如果不能启动,那就需要调试 Linux 内核。启动Linux 内核用到的外设不多,一般就 DRAM(Uboot 都初始化好的)和串口。作为终端使用的串口一般都会参考半导体厂商的 Demo 板。
    5. 修改相应的驱动。重点是网络驱动,如果是处理器内部 MAC+外部 PHY 这种网络方案的话,只要设置好复位引脚、 PHY 地址信息基本上都可以驱动起来。
    6.  Linux 内核启动以后需要根文件系统,如果没有根文件系统的话肯定会崩溃,所以确定 Linux内核移植成功以后就要开始根文件系统的构建。


    网站公告

    今日签到

    点亮在社区的每一天
    去签到