文章目录
- 一、安装相应依赖包
- 二、下载相应的内核版本库
- (1)讲解官网内核分支
- (2)下载内核版本库
- (3)内核目录文件讲解
- 三、开始内核移植过程
- (1)步骤一、修改默认架构和默认交叉编译器
- (2)步骤二、添加需要忽略的文件类型
- (3)步骤三、添加设备树以及补丁文件
- 【1】添加设备树
- 【2】添加补丁文件
- (4)步骤四、添加 defconfig 配置文件
- 【1】/arch/arm/configs
- 【2】imx_v7_defconfig
- 四、编译结果
借鉴学长的博客然后加上自己的理解:[内核移植]内核移植过程
-
开发板介绍:
IGKBoard(IoT Gateway Kit Board)ARM Linux物联网网关开发板。此开发板基于 NXP i.MX6ULL系列 Cortex-A7 高性能处理器设计。 -
移植内核版本:
root@igkboard:~# uname -a Linux igkboard 5.15.32 #3 SMP PREEMPT Sun Apr 9 16:17:47 CST 2023 armv7l armv7l armv7l GNU/Linux
-
内核官网: The Linux Kernel Archives
一、安装相应依赖包
在移植 Linux 内核时,需要安装 lzop、libncurses5-dev 和 libssl-dev 这三个包如下:
- lzop:
sudo apt-get install lzop
内核编译过程中需要使用到 lzop 压缩工具,以便将内核镜像等文件压缩成 .lzop 格式。 - libncurses5-dev:
sudo apt-get install libncurses5-dev
内核编译过程中需要使用 ncurses 库,以便在字符终端上显示菜单界面。 - libssl-dev:
sudo apt-get install libssl-dev
在内核中有一些功能需要使用 OpenSSL 库,例如 TLS 加密协议、数字证书等。
这三个包的安装是为了保证内核编译过程中所需的软件工具和库都具备。如果没有安装这些包,可能会导致在编译内核时出现相关的错误或警告信息。因此,在进行内核移植之前,需要先检查和安装相关的依赖包。
二、下载相应的内核版本库
(1)讲解官网内核分支
Kernel.org 是一个专门用于存储和发布 Linux 内核源代码的网站,也是 Linux 内核最早和最主要的代码托管平台之一。在 Kernel.org 上可以找到各个版本的 Linux 内核源码包以及相应的补丁包。另外,Kernel.org 还提供了内核开发和维护所需的各种工具和资源。
进入官网: The Linux Kernel Archives
- Mainline 分支:也称为主线分支,是 Linux 内核开发的主要分支。这里的代码是最新、最先进的,包含了最新的特性、修复和改进。但也因此可能会不够稳定,存在一定的风险。
- Stable 分支:该分支是针对针对生产环境的 bug 修复版本。一旦主线分支的代码出现问题,就会立刻在 Stable 分支中寻找并修复 bug。稳定版本相对来说比较可靠,但并不包含最新的特性。
- Longterm 分支:该分支是长期维护版本,保持与主线分支相同的稳定性和实用性,并在此基础上提供长时间的维护支持。适合希望长期稳定运行的企业或组织使用。
- Linux-next 分支:该分支包含了下一个内核版本的候选代码,也可以视为开发版的分支。优先考虑最新的特性、驱动程序和平台支持,但相较于 Mainline 分支更加不稳定。
所以我们一般选择比较稳定的长期维护的Lingtrem分支下的版本。
(2)下载内核版本库
点击你想下载的版本库:
wget命令下载:
然后就可以看见我们的压缩包文件(我下载的是自己实验室版本的,大家根据自己的版本下载):
wangdengtao@wangdengtao-virtual-machine:~/kernel$ ls
linux-imx linux-imx.tar.xz
要解压 .tar.xz 文件,可以使用 tar 命令行工具和 xz 工具一起进行解压。
如果系统尚未安装 tar 和 xz 工具,可以在 Ubuntu 或 Debian 系统上通过以下命令来安装:sudo apt-get install tar xz-utils
安装完成后,可以使用以下命令来解压 .tar.xz 文件:tar -xf filename.tar.xz
(3)内核目录文件讲解
我们进入解压缩的内核文件夹下,可以看见很多的文件,我们着重讲解一些比较重要的文件夹:
wangdengtao@wangdengtao-virtual-machine:~/kernel/linux-imx$ ls
arch CREDITS fs Kbuild LICENSES mm modules.order samples System.map vmlinux
block crypto include Kconfig MAINTAINERS modules.builtin Module.symvers scripts tools vmlinux.o
certs Documentation init kernel MAINTAINERS.NXP modules.builtin.modinfo net security usr vmlinux.symvers
COPYING drivers ipc lib Makefile modules-only.symvers README sound virt
- arch:arch 目录是一个非常重要的目录,其中包含了 Linux 内核所有体系结构相关的代码,每一个体系结构(架构)都有一个相应的子目录。这些子目录包括了体系结构相关的代码、头文件和 Makefile 等。例如,在 arch/x86 这个目录下,存放的是 x86 架构的 CPU、设备驱动、指令集体系结构等代码,而在 arch/arm64 这个目录下则是 arm64 架构的代码和头文件等。
- block:该目录包含块设备I/O和缓存管理的代码。
- crypto:该目录包含了加密和 hash 算法的实现。
- drivers:该目录包含了大部分设备驱动程序的源代码。
- fs:该目录包含了 Linux 文件系统的代码,包括虚拟文件系统、磁盘文件系统和网络文件系统等。
- include:该目录包含了内核头文件,为内核提供了各种数据类型与宏定义。
- init:该目录包含内核启动和初始化代码。
- kernel:该目录包含了大部分内核的核心功能,例如进程调度、内存管理、时间管理等。
- mm:该目录包含了内存管理的代码,包括虚拟内存和物理内存的管理。
- net:该目录包含了网络协议栈的实现。
- security:该目录包含了 Linux 内核安全子系统的代码。
三、开始内核移植过程
i.MX6ULL是i.MX系列处理器中的一种,其内核移植的具体代码步骤如下:
- 下载 i.MX6ULL 平台的开发板原理图、CPU 手册、芯片手册等硬件资料,了解该平台的硬件信息。
- 下载适用于 i.MX6ULL 处理器的 Linux 内核源码,并将其解压到本地目录中。
- 安装交叉编译工具链,以便针对 i.MX6ULL 处理器进行交叉编译。可使用 Ubuntu 下的 apt-get 工具进行安装,例如:
sudo apt-get install gcc-arm-linux-gnueabihf
- 使用 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xxxconfig 命令配置内核选项,包括交叉编译器、CPU架构、驱动程序和文件系统等选项。这里需要根据实际硬件情况进行相应的配置,我们下面会详细讲解。
- 编译内核并生成 zImage 和 xxx.dtb 等文件。其中xxx.dtb 文件是设备树文件,需要根据开发板的硬件资料编写并编译。
- 将 zImage 和 xxx.dtb 文件拷贝到 TFTP 服务器的目录下。在开发板上启动 U-Boot 并设置启动参数,以便从 TFTP 服务器下载内核并启动。
- 启动开发板,观察内核启动过程,确保内核启动成功。如果内核启动失败,则需要检查设备树文件和配置选项是否正确,以及驱动程序是否正确编译和加载。
总体而言,在移植 i.MX6ULL 内核时,需要关注交叉编译工具链、内核选项配置、设备树的编写和使用等方面。需要根据实际硬件情况进行调试和优化。
(1)步骤一、修改默认架构和默认交叉编译器
针对 ARM 架构的处理器进行编译的相关命令,解释一下【ARCH 参数指定了编译的目标处理器架构为 ARM,CROSS_COMPILE 参数指定了交叉编译工具链的路径。】:
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- distclean
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- xxx_defconfig
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- -j16
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- distclean:该命令用于清理之前编译生成的文件,以便重新开始编译。
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- xxx_defconfig:该命令用于生成配置文件,其中 xxx 表示具体的板子型号或配置文件名称。生成的配置文件包含了编译内核所需的各种选项和参数。如果不指定配置文件,则使用默认的配置。
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- -j4:该命令用于编译内核,并指定同时使用的线程数为 4。其中,-j 参数用于指定并发编译的线程数。这样可以加速编译过程,提高编译效率。最终编译成功后,会在当前目录下生成内核镜像、设备树等文件。
总之,这些命令是在 Linux 系统下进行 ARM 架构的内核移植时常用的命令,需要根据具体的情况进行修改和适配。
但是为了方便,不打打这三串这么长的命令,我们需要在根源码目录下修改Makefile(添加下面的代码):
386 ARCH = arm
387 CROSS_COMPILE ?= /usr/bin/arm-linux-gnueabihf-
这里的交叉编译链的路径需要注意:如果你是直接用sudo apt-get install gcc-arm-linux-gnueabihf
安装的交叉编译器的话就用我上面的路径,如果不是的话需要自己去找(你自己应该知道在哪儿的)
修改之后我们后面只需要执行下面的三个命令编译内核就可:
make distclean
make xxx_defconfig
make -j4
(2)步骤二、添加需要忽略的文件类型
打开Makefile,添加下面需要在编译过程中忽略的文件类型【有的话就补充,没有的话就添加】:
-o -name '*.ko.*' \
-o -name '*.dtbo' \
-o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
-o -name '*.dwo' -o -name '*.lst' \
-o -name '*.su' -o -name '*.mod' \
解释:
内核 Makefile 中的这些 -o 选项是用于指定不需要编译或链接的文件类型,即需要忽略的文件类型。在编译内核时,由于内核代码量庞大,可能会生成大量的中间文件、临时文件和不必要的输出文件,这些文件会占用存储空间,造成混乱,同时也会增加编译时间和链接时间。为了避免这些问题,在内核 Makefile 中可以使用 -o 选项指定不需要编译或链接的文件类型,以达到减少文件存储和缩短编译时间的效果。
例如,在内核编译过程中,会生成大量的模块文件(.ko 文件)、设备树二进制文件(.dtb)、调试信息文件(.dwo)等,而这些文件对于内核的编译和链接来说并不是必需的,因此可以将它们忽略掉,从而减少编译和链接所需的时间和空间。
此外,某些后缀名为 .mod 的文件,如 .mod.c、.mod.o 和 *.mod.map 等文件,是由内核构建系统创建的,用于跟踪内核模块的依赖关系,并在模块加载时加载符号表等信息。这些文件不需要在编译过程中进行链接,因此也可以通过在 Makefile 中使用 -o 选项来排除它们。
在整个内核构建过程中,使用 -o 选项可以帮助开发者更好地管理内核代码和中间生成文件,保持代码库的整洁性,降低构建成本,提高构建效率。
(3)步骤三、添加设备树以及补丁文件
【1】添加设备树
打开 /arch/arm/boot/dts
添加 igkboard 自己的设备树文件 igkboard.dts
这个设备树文件【直接拿的开头介绍的学长博客中的代码】:
/*
* Device Tree Source for LingYun IGKBoard(IoT Gateway Kit Board)
* Based on imx6ul-14x14-evk.dts/imx6ul-14x14-evk.dtsi
*
* Copyright (C) 2022 LingYun IoT System Studio.
* Author: Linke<731253265@qq.com>
*/
/dts-v1/;
#include "imx6ull.dtsi"
/ {
model = "LingYun IoT System Studio IoT Gateway Board";
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
chosen {
stdout-path = &uart1;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0xa000000>;
linux,cma-default;
};
};
mq2 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "my_mq2";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mq2>;
mq2-gpio = <&gpio5 1 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio5>;
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
status = "okay";
};
buzzer: pwm-buzzer {
compatible = "pwm-beeper";
pwms = <&pwm2 0 500000>;
status = "okay";
};
pxp_v4l2 {
compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
status = "okay";
};
reg_sd1_vmmc: regulator-sd1-vmmc {
compatible = "regulator-fixed";
regulator-name = "VSD_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
off-on-delay-us = <20000>;
enable-active-high;
};
reg_peri_3v3: regulator-peri-3v3 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_peri_3v3>;
regulator-name = "VPERI_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio5 2 GPIO_ACTIVE_LOW>;
/*
* If you want to want to make this dynamic please
* check schematics and test all affected peripherals:
*
* - sensors
* - ethernet phy
* - can
* - bluetooth
* - wm8960 audio codec
* - ov5640 camera
*/
regulator-always-on;
};
reg_can_3v3: regulator-can-3v3 {
compatible = "regulator-fixed";
regulator-name = "can-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
reg_vref_adc: regulator@2 {
compatible = "regulator-fixed";
regulator-name = "VREF_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
};
/*+--------------+
| Misc Modules |
+--------------+*/
&snvs_poweroff {
status = "okay";
};
&snvs_pwrkey {
status = "okay";
};
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
status = "okay";
};
&pwm2 {
#pwm-cells = <2>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm2>;
status = "okay";
};
/*+-------------------+
| i2c Device Module |
+-------------------+*/
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
};
/*+-------------------+
| iio Device Module |
+-------------------+*/
&adc1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_adc1>;
num-channels = <2>;
vref-supply = <®_vref_adc>;
status = "okay";
};
/*+---------------+
| Camera Module |
+---------------+*/
&i2c2 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
ov5640: ov5640@3c {
compatible = "ovti,ov5640";
reg = <0x3c>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_csi1 &pinctrl_camera_clock>;
clocks = <&clks IMX6UL_CLK_CSI>;
clock-names = "csi_mclk";
csi_id = <0>;
mclk = <24000000>;
mclk_source = <0>;
status = "disabled";
port {
ov5640_ep: endpoint {
remote-endpoint = <&csi1_ep>;
};
};
};
};
&csi {
status = "disabled";
port {
csi1_ep: endpoint {
remote-endpoint = <&ov5640_ep>;
};
};
};
/*+--------------+
| Audio Module |
+--------------+*/
&clks {
assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <786432000>;
};
/*+------------------+
| Ethernet Modules |
+------------------+*/
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-supply = <®_peri_3v3>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-supply = <®_peri_3v3>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-id0022.1560";
reg = <0>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET_REF>;
clock-names = "rmii-ref";
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-id0022.1560";
reg = <1>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET2_REF>;
clock-names = "rmii-ref";
};
};
};
&can1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan1>;
xceiver-supply = <®_can_3v3>;
status = "okay";
};
&can2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan2>;
xceiver-supply = <®_can_3v3>;
status = "okay";
};
/*+---------------+
| USB interface |
+---------------+*/
&usbotg1 {
dr_mode = "otg";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb_otg1>;
status = "okay";
};
&usbotg2 {
dr_mode = "host";
disable-over-current;
status = "okay";
};
&usbphy1 {
fsl,tx-d-cal = <106>;
};
&usbphy2 {
fsl,tx-d-cal = <106>;
};
/*+------------------+
| USDCHC interface |
+------------------+*/
&usdhc1 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc1>;
pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
keep-power-in-suspend;
wakeup-source;
vmmc-supply = <®_sd1_vmmc>;
status = "okay";
};
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
non-removable;
bus-width = <8>;
keep-power-in-suspend;
wakeup-source;
status = "okay";
};
/*+----------------------+
| Basic pinctrl iomuxc |
+----------------------+*/
&iomuxc {
pinctrl-names = "default";
pinctrl_camera_clock: cameraclockgrp {
fsl,pins = <
MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
>;
};
pinctrl_csi1: csi1grp {
fsl,pins = <
MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088
MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088
MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088
MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088
MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088
MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088
MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088
MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088
MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088
MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088
>;
};
pinctrl_enet1: enet1grp {
fsl,pins = <
MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
>;
};
pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
>;
};
pinctrl_flexcan1: flexcan1grp{
fsl,pins = <
MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
>;
};
pinctrl_flexcan2: flexcan2grp{
fsl,pins = <
MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020
MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020
>;
};
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO02__I2C1_SCL 0x4001b8b0
MX6UL_PAD_GPIO1_IO03__I2C1_SDA 0x4001b8b0
>;
};
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
>;
};
pinctrl_lcdif_dat: lcdifdatgrp {
fsl,pins = <
MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79
MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79
MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79
MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79
MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79
MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79
MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79
MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79
MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79
MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79
MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79
MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79
MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79
MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79
MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79
MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79
MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79
MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79
MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79
MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79
MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79
MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79
MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79
MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79
>;
};
pinctrl_lcdif_ctrl: lcdifctrlgrp {
fsl,pins = <
MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79
MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79
MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79
MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79
/* used for lcd reset */
MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79
>;
};
pinctrl_peri_3v3: peri3v3grp {
fsl,pins = <
MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b0
>;
};
pinctrl_pwm1: pwm1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0
>;
};
pinctrl_pwm7: pwm7grp {
fsl,pins = <
MX6UL_PAD_JTAG_TCK__PWM7_OUT 0x110b0
>;
};
pinctrl_pwm8_nbiot: pwm8nbiotgrp {
fsl,pins = <
MX6UL_PAD_JTAG_TRST_B__PWM8_OUT 0x110b0
>;
};
pinctrl_spi4: spi4grp {
fsl,pins = <
MX6UL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1
MX6UL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1
MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1
MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000
>;
};
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
>;
};
pinctrl_usb_otg1: usbotg1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x17059
>;
};
pinctrl_usdhc1: usdhc1grp {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059
>;
};
pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
>;
};
pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
>;
};
pinctrl_usdhc2: usdhc2grp {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x17059
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
>;
};
pinctrl_usdhc2_8bit: usdhc2grp_8bit {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10069
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x17059
MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x17059
MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x17059
MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x17059
>;
};
pinctrl_usdhc2_8bit_100mhz: usdhc2grp_8bit_100mhz {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100b9
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170b9
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9
MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170b9
MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170b9
MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170b9
MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170b9
>;
};
pinctrl_usdhc2_8bit_200mhz: usdhc2grp_8bit_200mhz {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100f9
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170f9
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9
MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170f9
MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170f9
MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170f9
MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170f9
>;
};
pinctrl_spi_uart8: spi_uart8_grp {
fsl,pins = <
MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK 0x10b0
MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI 0x10b0
MX6UL_PAD_LCD_DATA23__ECSPI1_MISO 0x10b0
MX6UL_PAD_LCD_DATA21__GPIO3_IO26 0x10b0
>;
};
pinctrl_mq2: mq2_grp {
fsl,pins = <
MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x17059
>;
};
pinctrl_pwm2: pwm2grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO09__PWM2_OUT 0x110b0
>;
};
pinctrl_adc1: adc1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
>;
};
};
然后修改(添加)这个目录下的Makefile文件:
【定义 igkboard 设备树的编译选项和编译输出目录,并将 igkboard.dtb 添加到设备树文件列表中进行编译。同时,还将 overlays 目录添加到子目录列表中,表示编译完成后需要将该目录下的文件一同输出到内核镜像中】
DTC_FLAGS_igkboard := -@
dtb-$(CONFIG_SOC_IMX6UL) += igkboard.dtb
subdir-$(CONFIG_SOC_IMX6UL) += overlays
在内核的 Makefile 中定义了一个名为 DTC_FLAGS_igkboard 的变量,并将其设置为 -@。之后通过将 igkboard.dtb 添加到 dtb - $ (CONFIG_SOC_IMX6UL) 变量中,表示该设备树二进制文件将会被编译。同时,将 overlays 添加到 subdir-$(CONFIG_SOC_IMX6UL) 变量中,表示该目录下的文件也将会被编译。
具体来说,DTC_FLAGS_igkboard 是一个 DTC 程序(Device Tree Compiler)的编译选项,用于定义 igkboard 设备树的编译参数。其中,-@ 表示禁止 DTC 输出命令行信息。dtb-$ (CONFIG_SOC_IMX6UL) 是一个 Makefile 变量,表示在编译 soc_imx6ul 内核时需要生成的设备树文件列表。igkboard.dtb 是一个 igkboard 设备树的二进制文件,将会添加到设备树文件列表中进行编译。subdir-$ (CONFIG_SOC_IMX6UL) 则是一个 Makefile 变量,表示 soc_imx6ul 内核编译完成后需要生成的子目录列表。在该 Makefile 中,将 overlays 目录添加到 subdir-$(CONFIG_SOC_IMX6UL) 变量中,表示编译完成后需要将该目录下的文件一同输出到内核镜像中。
【2】添加补丁文件
在/arch/arm/boot/dts
下添加overlays
文件夹,在这个文件夹下的添加的 dts 文件,我们会在之后对其 Makefile 进行修改,并将其编译成 dtbo 文件。
如果对设备树插件不理解的可以参考这篇文章:
GIC中断控制器、设备树插件(Device Tree Overlay)以及内核定时器介绍
wangdengtao@wangdengtao-virtual-machine:~/kernel/linux-imx/arch/arm/boot/dts/overlays$ cat i2c1.dts
/dts-v1/;
/plugin/;
#include "../imx6ul-pinfunc.h"
/* 40-pin extended GPIO, I2C1 interfaces */
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
i2c_sht20@40{
compatible = "imx_i2c_sht20";
status = "okay";
reg = <0x40>;
};
};
&iomuxc {
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO02__I2C1_SCL 0x4001b8b0
MX6UL_PAD_GPIO1_IO03__I2C1_SDA 0x4001b8b0
>;
};
};
我添加了这一个i2c的设备树插件。
在 /arch/arm/boot/dts/overlays
文件夹中添加 Makefile 文件,并添加如下内容,用于将该文件下的所有 dts 文件都编译成 dtbo 文件,作为备用,给 igkboard.dtb 打补丁:
# SPDX-License-Identifier: GPL-2.0
# required for overlay support
DTC_FLAGS += -@
dtb-y += i2c1.dtbo
(4)步骤四、添加 defconfig 配置文件
到目录/arch/arm/configs
下,将imx_v7_defconfig
修改为igkboard_defconfig
即可。
【1】/arch/arm/configs
/arch/arm/configs 目录是 Linux 内核代码中专门用于存放 ARM 架构相关的配置文件的目录。在 Linux 内核的构建过程中,这些配置文件可以通过编译器和链接器的指定来生成可执行的内核镜像,并被用于驱动硬件设备和支持各种系统功能。
这些 ARM 架构的配置文件位于 /arch/arm/configs 目录下,以 .config 文件格式存储。这些配置文件通常包含内核构建选项、系统设置、外围设备驱动程序、虚拟文件系统等设置。在进行内核编译时,使用 make ARCH=arm menuconfig 命令可以通过菜单界面对这些选项进行选择和配置。
在 ARM 平台的开发中,使用这些预定义的 ARM 配置文件可以大大加快内核构建的速度,因为这些配置文件已经包含了 ARM 硬件平台的主要特性和功能。同时,这些 ARM 配置文件也为开发者提供了一个模板,可以调整内核的编译选项、功能和驱动程序,以满足特定的需求和限制。
总之,/arch/arm/configs 目录中存储着一些预定义的 ARM 架构配置文件,这些配置文件包含了内核构建选项、系统设置、外围设备驱动程序、虚拟文件系统等设置,可以帮助开发者快速构建适用于特定 ARM 硬件平台的 Linux 内核镜像。
【2】imx_v7_defconfig
imx_v7_defconfig
是 Linux 内核针对 i.MX 系列 ARMv7 处理器的一个默认配置文件。存放位置在 /arch/arm/configs/imx_v7_defconfig
。
该配置文件包含了内核编译所需的所有选项,以生成适用于 i.MX 系列 ARMv7 处理器的预定义内核二进制镜像。这些选项涵盖了以下方面:
- CPU 架构和型号(ARMv7 Cortex-A 核心)
- 内核启动参数(内核命令行等)
- 内核功能开关(调试信息、内存管理、调度程序、定时器、时钟、IRQ 控制器、访问控制、加密支持、虚拟文件系统等)
- 文件系统支持(EXT4、FAT、NTFS、SquashFS、JFFS2、UBIFS 等)
- 块设备驱动程序(MMC/SD/SDIO、NAND、eMMC、SPI NOR 等)
- 网络驱动程序(有线网卡、Wi-Fi、蓝牙等)
- 开发者可以通过命令
make ARCH=arm imx_v7_defconfig
生成内核配置文件 .config,然后可 - 使用
make ARCH=arm menuconfig
或其他内核配置工具对其进行修改和优化。之后,运行 make ARCH=arm 即可开始编译 i.MX 系列 ARMv7 处理器的 Linux 内核。
总之,imx_v7_defconfig 是针对 i.MX 系列 ARMv7 处理器的默认内核配置文件,包含了所有内核编译所需的选项。它为开发者提供了一个快速生成适用于 i.MX 系列 ARMv7 处理器的 Linux 内核镜像的方式。
四、编译结果
使用之前提到的命令编译内核:
make distclean
make igkboard_defconfig
make -j4
等待一定的时间之后我们可以在内核源码文件夹下看到 vmlinux 以及 /arch/arm/boot 文件夹下看到 Image 和 zImage 文件。
对于内核文件,vmlinux 就是最原始的内核文件,但是该文件太大,不利于传输,因此对其进行压缩,这个过程是,先利用 objcopy 取消掉 vmlinux 中的一些信息,比如符号之类的,然后生成 Image 文件,然后用 gzip 工具,对=Image 文件进行压缩,最后生成 zImage 文件,然后将 zImage 烧录到开发板即可。
wangdengtao@wangdengtao-virtual-machine:~/kernel/linux-imx/arch/arm/boot$ ls
bootp compressed deflate_xip_data.sh dts Image install.sh Makefile zImage
然后将igkboard.dts和zImage文件放在tftp目录下,tftp网络启动试着启动。
tftp网络启动不会的参考这篇文章:Linux嵌入式uboot使用tftp网络启动加载zImage、设备树
多余:对vlinux的理解:
vmlinux 是 Linux 内核编译成功后生成的一个文件,它是内核代码经过编译、链接后的可执行文件。
在 Linux 内核编译的过程中,内核源代码被先进行预处理、编译、汇编等过程生成目标文件,然后在链接阶段将这些目标文件链接成可执行文件。最终生成的可执行文件就是 vmlinux。
vmlinux 是一个非压缩的 ELF 格式(Executable and Linkable Format)的可执行文件,包含了内核的所有代码和数据。它不同于 bzImage 或 zImage,这两个文件是经过压缩的内核镜像文件,可以直接用于引导启动操作系统。
一般来说,如果用户要将内核文件放到 bootloader 中引导 bootloader 的话,需要将 vmlinux 文件进行压缩处理,然后生成 bzImage 或 zImage 文件。另外,内核开发者也可以通过 objdump 等工具分析 vmlinux 文件,以了解内核代码的结构和实现细节。