当前位置: 首页 > news >正文

IMX6ULL的Linux内核移植

在前面的博客中我们已经分别介绍了U-Boot 移植、U-Boot 启动流程分析以及Linux 内核启动流程分析。在这些内容发布后也有一些读者提出了几个比较常见的问题为什么 U-Boot 源码和 Linux 内核源码中都有设备树 DTS 文件系统启动时到底使用的是哪一个设备树Linux 内核在编译时又是如何根据配置去编译各个目录下驱动程序的这些问题都和后续的 Linux 内核移植密切相关。因此在正式介绍 Linux 移植之前我们先对这些基础问题做一个统一说明方便后面理解内核移植、设备树适配以及驱动裁剪的整体流程。1、为什么 U-Boot 和 Linux 内核源码中都有 DTS启动时到底使用哪一个U-Boot 和 Linux 内核源码中都有设备树 DTS 文件但它们的作用不同。①U-Boot 中的设备树主要是给U-Boot 自己使用的。在编译 U-Boot 时DTS 会被编译进镜像中最终生成u-boot-dtb.imx。U-Boot 运行时会解析自己镜像中的设备树并根据设备树信息匹配、probe 对应的驱动用来初始化板子的基础硬件。②而 Linux 内核使用的设备树一般是由Linux 源码中的 DTS 编译生成的 DTB 文件。这个 DTB 会由 U-Boot 单独加载到内存中然后传递给 Linux 内核使用。这里需要注意zImage和dtb是两个不同的文件。编译 Linux 内核时内核镜像和设备树是分开生成的启动时也是分开加载的。例如setenv kernel_addr_r 0x80800000 setenv fdt_addr_r 0x83000000其中kernel_addr_r是zImage的加载地址fdt_addr_r是dtb的加载地址。U-Boot 会分别加载它们然后通过bootz启动 Linux 内核并把设备树地址传给内核。2、Linux 内核编译时是如何决定编译哪些驱动的Linux 内核编译驱动的方式和前面介绍 U-Boot 编译时的逻辑类似都是通过Kconfig Makefile来决定的。以内核默认配置文件为例arch/arm/configs/imx_v7_angus_defconfig执行配置命令后Kconfig 会根据这个defconfig生成最终的.config文件。.config中记录了哪些驱动需要编译、哪些不编译以及哪些驱动需要编译成模块。随后内核编译系统会根据.config生成include/config/auto.conf真正编译时各级目录下的 Makefile 会读取这些配置项决定是否进入对应目录以及是否编译对应的驱动源码。目录IMX6ULL的Linux内核移植Linux内核移植总结Linux 内核移植补充第一阶段i2c_adapter 与 i2c_client 初始化第二阶段I2C 读取数据与 input 子系统上报数据总结触摸屏适配IMX6ULL的Linux内核移植通过上面的解答再结合之前对Linux 内核编译和Linux 内核启动流程的分析大家应该可以发现Linux 内核移植中最重要的两个文件就是defconfig 配置文件和设备树 DTS 文件。第一个是内核配置文件arch/arm/configs/imx_v7_angus_defconfig它主要决定 Linux 内核编译时需要开启哪些功能、编译哪些驱动。第二个是设备树文件arch/arm/boot/dts/imx6ull-14x14-angus.dts它主要用来描述开发板上的硬件资源例如串口、网卡、MMC、I2C、SPI、GPIO 等外设。Ubuntu 端编译并放入 TFTP 目录make 100ask_imx6ull_defconfig //取决于你使用什么**deconfig文件这只是一个例子 make -j4 zImage dtbs sudo cp arch/arm/boot/zImage /home/book/tftpboot/ sudo cp arch/arm/boot/dts/imx6ull-14x14-angus.dtb /home/book/tftpboot/ 检查文件 ls -l /home/book/tftpboot/zImage /home/book/tftpboot/imx6ull-14x14-angus.dtb板子端在 U-Boot 中下载并启动 Linuxsetenv ipaddr 192.168.1.88 setenv serverip 192.168.1.66 setenv bootargs consolettymxc0,115200 root/dev/mmcblk1p2 rootwait rw 更新 u-boot-dtb.imx 后在 U-Boot 中先用较小的数据块测试 setenv tftpblocksize 512 setenv tftptimeoutcountmax 100 tftp 0x80800000 zImage 如果可以下载成功再测试默认大块传输 tftp 0x80800000 zImage tftp 0x83000000 imx6ull-14x14-angus.dtb bootz 0x80800000 - 0x83000000Linux内核移植总结本次工作主要是通过U-Boot 网络启动方式来验证移植后的 Linux 内核。首先需要调通板卡网口使开发板能够与 Ubuntu 虚拟机中的 TFTP 服务器正常通信。随后在 U-Boot 中通过tftp命令将 Linux 内核镜像zImage下载到内存地址0x80800000再将与 ANGUS 板硬件匹配的设备树文件imx6ull-14x14-angus.dtb下载到0x83000000。最后执行bootz 0x80800000 - 0x83000000启动 Linux 内核。在当前板级默认环境中image默认设置为zImagefindfdt会根据ANGUS 14X14板卡信息自动设置默认设备树文件名为imx6ull-14x14-angus.dtb因此执行默认网络启动流程时U-Boot 会加载zImage和imx6ull-14x14-angus.dtb这两个文件。需要注意的是文件名本身并不是强制固定的。我们也可以手动执行tftp命令或者修改image、fdt_file等环境变量来指定其他内核镜像或设备树文件。真正必须满足的是内核镜像格式能够被bootz启动设备树内容必须与当前开发板硬件匹配Linux 内核移植补充在完成 Linux 内核基本移植后系统已经能够正常启动但在后续功能验证过程中发现触摸屏暂时无法正常工作。因此本文将进一步补充触摸屏的适配过程主要分析触摸屏驱动、设备树节点、I2C 总线、中断引脚以及复位引脚等相关配置最终实现触摸屏在开发板上的正常使用。在本次触摸屏适配过程中可以先从设备树分析触摸屏的挂载关系。触摸屏属于 I2C 设备其设备树节点如下i2c2 { gt9xx5d { compatible goodix,gt9xx; reg 0x5d; interrupts 5 IRQ_TYPE_EDGE_FALLING; }; };同时设备树中配置了如下 I2C 别名i2c1 i2c2;因此需要注意硬件上使用的是 I2C2 控制器但在 Linux 系统中会被注册为 i2c-1 总线。对应关系如下① 硬件控制器I2C2 ② Linux 总线编号i2c-1 ③ 触摸芯片GT9XX ④ I2C 从机地址0x5d第一阶段i2c_adapter 与 i2c_client 初始化Linux 启动时首先由 i2c-imx 控制器驱动初始化 I2C2并向 I2C core 注册对应的 i2c_adapter。由于设备树别名中将 i2c1 指向了 i2c2所以该控制器在系统中表现为 i2c-1。adapter 注册完成后I2C core 会继续解析 i2c2 节点下的子节点。根据 gt9xx5d 这个设备树节点内核会创建一个 i2c_client 设备。其中client-adapter 指向 i2c-1 对应的 i2c_adapterclient-addr 保存触摸芯片的 I2C 地址 0x5d。因此在内核中可以理解为i2c-1 总线上存在一颗地址为 0x5d 的 Goodix GT9XX 触摸屏设备。后续 Goodix 触摸屏驱动加载后会根据 compatible goodix,gt9xx 与该设备进行匹配。如果匹配成功就会调用驱动的 probe 函数并通过 i2c_client 与触摸芯片进行通信。设备树中的 i2c2 // 描述 i.MX6ULL 的 I2C2 控制器已启用 | -- i2c_imx_probe() // i.MX6ULL I2C 控制器驱动的 probe // 初始化 I2C2 寄存器、时钟、控制器中断和传输函数 | -- 建立 struct i2c_adapter | // adapter 表示“这一条可以收发 I2C 数据的总线” | // | // adapter.nr 1 | // 对外显示为 i2c-1 | -- i2c_add_numbered_adapter(i2c_imx-adapter) // 把 i2c-1 这条总线注册到 I2C core | -- /dev/i2c-1 | // 若 CONFIG_I2C_CHARDEVy | // 这是整条总线的用户态原始访问入口 | -- of_i2c_register_devices(adapter) // adapter 注册后遍历它下面的设备树子节点 | -- 找到 gt9xx5d // 内核知道 i2c-1 上声明了一颗地址 0x5d 的设备 | -- of_i2c_register_device() | // 读取 compatible 和 reg | -- i2c_new_device(adapter, info) // 创建 struct i2c_client | -- client-adapter adapter | // 该设备挂在哪条 I2C 软件总线对象上 | // 即 i2c-1 | -- client-addr 0x5d | // 访问该设备时使用的从机地址 | -- client-dev.of_node gt9xx5d | // 保存设备树配置来源 | -- device_register(client-dev) // 把该从设备加入 Linux 设备模型 | -- /sys/bus/i2c/devices/1-005d // 表示 i2c-1 上的 0x5d 设备需要注意的是/sys 和 /dev 并不是同一个概念。/sys 是 Linux 设备模型在用户空间的展示用来查看内核中已经注册的设备、设备挂在哪条总线上、绑定了哪个驱动以及设备相关属性。/dev 是字符设备或块设备提供给应用程序的访问入口。应用程序一般通过 open()、read()、write()、ioctl() 等系统调用访问 /dev 下的设备节点。有时我们会感觉 /sys 和 /dev 表示的是同一个设备是因为字符设备驱动通常会同时完成两件事第一通过 cdev_add() 建立主设备号、次设备号与 file_operations 的对应关系。第二通过 device_create() 将带有设备号的设备接口注册到 Linux 设备模型中。这样该设备会出现在 /sys/class/... 目录下如果系统启用了 devtmpfs或者使用 udev、mdev 处理设备事件还会自动生成对应的 /dev/... 节点。例如字符设备 charled 可能同时存在/sys/class/charled/charled/dev/charled其中/sys/class/charled/charled 表示该设备在 Linux 设备模型中的描述而 /dev/charled 是应用程序真正访问驱动的入口。但是总线上的硬件设备不能简单地和 /dev 节点一一对应。① 以 I2C 设备为例I2C 从设备在内核中通常由 struct i2c_client 表示可以在 /sys/bus/i2c/devices/... 中查看。例如触摸屏 GT9XX 挂载在 i2c-1 总线上地址为 0x5d系统中可能会看到/sys/bus/i2c/devices/1-005d。这表示 i2c-1 总线上存在一个地址为 0x5d 的 I2C 从设备但并不代表系统一定会生成 /dev/gt9xx。对于 GT9XX 触摸屏来说驱动通常不会直接导出 /dev/gt9xx而是通过 input 子系统上报触摸事件最终可能表现为/dev/input/eventX。②SPI 设备也是类似的。SPI 从设备可以在 /sys/bus/spi/devices/... 中查看只有绑定了 spidev 这类向用户空间导出字符设备接口的驱动时才会出现/dev/spidevB.C。③SDIO 设备也不一定有统一的 /dev/sdio... 节点。例如 SDIO Wi-Fi 通常注册为网络接口 wlan0而 SD 卡或 eMMC 这类存储设备则会导出为/dev/mmcblkN。因此可以简单理解为/sys描述内核设备模型中的设备、总线、驱动和属性。/dev提供应用程序访问字符设备或块设备的文件接口。总线设备注册后通常先体现在 /sys/bus/.../devices/ 中只有当驱动进一步向用户空间导出字符设备、块设备、input 设备或网络接口时用户程序才会看到对应的 /dev 节点或其他访问形式。所以/sys 中能看到某个设备只能说明它已经进入 Linux 设备模型至于 /dev 中是否存在对应节点要看驱动是否向用户空间导出了访问接口。第二阶段I2C 读取数据与 input 子系统上报数据当 GT9XX 驱动与设备树创建的 i2c_client 匹配成功后内核会调用驱动的 gtp_probe() 函数。gtp_probe() 是触摸屏驱动的一次性初始化函数主要负责完成触摸芯片上电、硬件复位、I2C 通信检测、输入设备注册以及中断申请等工作。gtp_probe() 首先读取设备树中的复位 GPIO、中断 GPIO、坐标范围和相关配置参数然后给触摸芯片上电并通过 RESET 和 INT 引脚完成 GT9XX 的硬件复位。复位完成后驱动会利用 i2c_client 中保存的 I2C adapter 和从机地址通过 I2C 访问 GT9XX 寄存器以确认芯片是否能够正常通信并进一步读取芯片 ID、固件版本和面板配置信息。初始化过程中驱动还会注册 goodix-ts 输入设备并申请触摸中断处理函数。初始化成功后当用户触摸屏幕时GT9XX 会产生中断驱动进入 gtp_irq_handler()通过 I2C 读取本次触摸的坐标数据然后调用 input_report_abs() 和 input_sync() 将触摸事件上报给 input 子系统。input 子系统最终通过 evdev 接口生成 /dev/input/eventX 节点应用程序读取该节点即可获得标准的触摸事件。gtp_probe() // GT9XX 设备初始化总入口 | - gtp_parse_dt() | // 读取设备树中的 GPIO、中断类型、坐标范围和配置开关 | | | - gtp_parse_dt_coords() | // 读取 touchscreen-size-x/y、max-id、压力范围 | - gtp_power_init() | // 获取触摸屏电源 regulator | - gtp_power_on() | // 给 GT9XX 芯片上电 | - gtp_pinctrl_init() | // 获取复位脚和中断脚的引脚状态 | - gtp_request_io_port() | // 申请 reset-gpiosGPIO5_IO02、irq-gpiosGPIO1_IO05 | - gtp_reset_guitar() | // 操作 RESET/INT 引脚使 GT9XX 芯片硬件复位 | | | - RESET 拉低 - 延时 - RESET 拉高 | // 让触摸芯片重新启动 | - gtp_i2c_test() | // 读取触摸芯片寄存器验证 I2C 通信是否正常 | | | - 若连续失败 | | | - 打印 Failed communicate with IC use I2C | // 优先检查地址、SCL/SDA、复位脚和供电 | - gtp_get_fw_info() | // 读取芯片产品 ID、固件版本、sensor_id | - gtp_init_panel() | // 初始化触摸面板配置 | | | - 当前 DTS: goodix,driver-send-cfg 0 | | | - 仅读取芯片内部已有配置 | // 不会使用 DTS 中 goodix,cfg-group0/1/2 下发新参数 | - gtp_request_input_dev() | // 创建 Linux input 设备 goodix-ts | | | - input_mt_init_slots() | | // 建立多点触摸 slot当前使用 Type-B 协议 | | | - input_set_abs_params() | | // 设置 X/Y/压力/触点 ID 的上报范围 | | | - input_register_device() | // 注册 /dev/input/eventX 设备 | - gtp_request_irq() | // 申请 GPIO1_IO05 的触摸中断 | | | - request_threaded_irq(..., gtp_irq_handler, ...) | // 中断触发后进入线程化处理函数 | - gtp_work_control_enable(true) // 初始化完成允许开始处理触摸事件总结首先I2C 控制器驱动会注册一个i2c_adapter用来表示一条 I2C 总线。然后内核根据设备树中的 gt9xx 节点创建 i2c_client用来表示挂载在这条 I2C 总线上的 GT9XX 触摸芯片。GT9XX 驱动通过这个i2c_client 与触摸芯片进行 I2C 通信读取触摸坐标、触点数量和触摸状态等数据。读取到触摸数据后驱动会将这些数据上报给 input 子系统。input 子系统再生成 /dev/input/eventX 节点用户空间应用程序最终通过读取该节点获取触摸事件。简单来说就是注册 i2c_adapter → 创建 i2c_client → I2C 读取触摸数据 → input 子系统上报 → 用户读取 /dev/input/eventX。触摸屏适配通过前面的分析可以知道GT9XX 触摸屏是一个 I2C 输入设备。因此触摸屏适配的主要工作就是将 GT9XX 驱动移植到当前 Linux 内核中并通过 Kconfig、Makefile 和设备树完成驱动的编译、加载和匹配。GT9XX 触摸屏驱动移植步骤如下1. 修改默认配置文件在arch/arm/configs/imx_v7_angus_defconfig文件中添加CONFIG_TOUCHSCREEN_GT9XXy CONFIG_TOUCHSCREEN_GT9XX_UPDATEy CONFIG_TOUCHSCREEN_GT9XX_TOOLy这样执行 make imx_v7_angus_defconfig 后生成的 .config 中就会包含 GT9XX 触摸屏相关配置。2. 拷贝 GT9XX 驱动源码将已有的 gt9xx 驱动目录拷贝到当前内核源码中 cp -rfd ~/100ask_imx6ull-sdk/Linux-4.9.88/drivers/input/touchscreen/gt9xx/ ./drivers/input/touchscreen/ 拷贝后目录为 drivers/input/touchscreen/gt9xx/3. 修改 Kconfig在drivers/input/touchscreen/Kconfig文件中添加source drivers/input/touchscreen/gt9xx/Kconfig这一步的作用是让内核 Kconfig 系统能够解析 gt9xx 驱动自己的 Kconfig 文件从而识别 CONFIG_TOUCHSCREEN_GT9XX 等配置项。如果不添加这句make defconfig 时即使在 defconfig 中写了 CONFIG_TOUCHSCREEN_GT9XXyKconfig 也可能因为找不到该配置项定义而无法正确生成到 .config 中。4. 修改 Makefile在drivers/input/touchscreen/Makefile文件中添加obj-$(CONFIG_TOUCHSCREEN_GT9XX) gt9xx/这一步是告诉 Kbuild如果 .config 中启用了 CONFIG_TOUCHSCREEN_GT9XX就进入 gt9xx 目录编译触摸屏驱动。当 .config 中存在CONFIG_TOUCHSCREEN_GT9XXy。Kbuild 会将obj-$(CONFIG_TOUCHSCREEN_GT9XX) gt9xx/展开为obj-y gt9xx/于是 Kbuild 会进入drivers/input/touchscreen/gt9xx/。继续读取该目录下的 Makefile并编译 GT9XX 触摸屏驱动。整体流程可以概括为Kconfig 引入 gt9xx 配置项↓defconfig 默认选中 CONFIG_TOUCHSCREEN_GT9XX↓make defconfig 生成 .config↓Kbuild 读取 Makefile↓obj-$(CONFIG_TOUCHSCREEN_GT9XX) 展开为 obj-y↓进入 gt9xx 目录编译驱动↓GT9XX 驱动被编译进内核完成 GT9XX 触摸屏驱动的移植和配置后重新编译 Linux 内核并按照上一篇博客中介绍的内核移植流程将新生成的内核镜像和设备树文件更新到开发板中进行验证。make distclean make imx_v7_angus_defconfig make zImage -j4 make dtbs
http://www.zskr.cn/news/1398534.html

相关文章:

  • <数据集>yolo苹果叶片病害识别<目标检测>
  • 从‘小费’到‘泰坦尼克’:用Seaborn的boxplot快速探索3个经典数据集的秘密与异常
  • B91C2 是什么牌号?四川莱韦美特高强变形镁合金 B91C2 参数、命名、对标与应用全解读
  • 基数排序:高效稳定的数字排序算法
  • 跟着 MDN 学CSS day_19:(实战挑战之内容面板的尺寸与装饰)
  • 2026年4月国内做得好的光伏连接件厂商找哪家,连续模具/模具/冲压件/汽车模具/汽车配件/金属配件,光伏连接件厂家手机 - 品牌推荐师
  • Air1601 LCD 显示开发全解析
  • 告别手写Shader!ShaderGraph可视化制作卡通风格水体(URP管线配置避坑)
  • 【C++进阶】vector 类从入门到精通:核心接口与内存机制实战指南
  • 告别Alt+F2失灵!手把手教你为UE4独立游戏开启Nvidia Ansel全景截图功能(适配新旧驱动)
  • Java语言概述
  • 保姆级图解:Android相机从App点击到出图的完整请求链路(以Camera Service为核心)
  • 别再单打独斗了!用CrewAI打造你的第一个多Agent“数字员工”团队(保姆级配置)
  • 不锈钢多功能管道修补器技术解析与行业选型参考:不锈钢单卡管道修补器/不锈钢双卡管道修补器/不锈钢板式修补器/不锈钢管道修补连接器/选择指南 - 优质品牌商家
  • 从零到心形响应:用Python+PyAudio模拟Endfire阵列,可视化你的第一个波束形成算法
  • 告别盲调!用S32K的FTM输入捕获精准测量PWM频率与占空比(附代码分析)
  • 从UCI数据集中选对‘第一课’:手把手教你用Python加载5个经典入门数据集(附代码)
  • 霍夫圆检测实战:用Python在工业零件图像中精准定位圆孔(附完整代码与调参指南)
  • Kafka Connect实战指南
  • 2026年值得尝试的6个简历制作网站推荐
  • 用Python爬虫+数据分析,揭秘《最后一片叶子》的词汇密码与情感曲线(附完整代码)
  • Arm ISP多上下文环境构建与优化实战指南
  • 量子机器学习在药物发现中的创新应用
  • 8051中断优化:ONEREGBANK指令原理与实践
  • 用Python+爬虫+数据分析,量化分析《最后一片叶子》的文本情感与角色关系
  • 别再死记硬背SMO公式了!用Python手写一个SVM分类器(从SMO变量选择到核函数实战)
  • MRI并行成像SENSE vs. GRAPPA:原理对比与Matlab仿真实验全记录
  • 别再死记硬背了!用这个‘水龙头’模型,5分钟彻底搞懂MOS管的三个工作区(截止、可变电阻、饱和)
  • ARMv8 SCTLR_EL1寄存器详解与内核开发实践
  • 银河麒麟V10/V10.1系统换源保姆级教程:告别官方源慢,一键配置国内镜像(附各版本源地址)