
手里这块RK3568的板子客户要求换一批外设接口固件里自带的设备树根本没法直接用。与其天天在厂家的SDK框里绕来绕去不如把内核构建的主动权拿回来——改代码、改配置、重编设备树、打包镜像、烧进去一套流程走通之后后面再调什么外设都顺了。这篇记录的就是RK3568平台手动构建Linux 4.19内核镜像、并针对实际硬件做设备树优化的完整过程。如果你也正在折腾RK3568感觉官方固件“能用但不够听话”这篇应该能帮你省不少时间。1. 动手之前RK3568与Linux 4.19这套组合怎么理解1.1 平台底细和为什么选4.19内核RK3568是瑞芯微一颗非常有代表性的中端SoC四核Cortex-A55主频最高能到1.8GHz左右自带GPU、NPU、VPU以及PCIe、SATA、双千兆GMAC、USB 3.0、多路MIPI/LVDS/RGB显示接口。这颗芯片最让人喜欢的地方在于接口齐全一个板子能把路由、工控、HMI、边缘计算、简单视觉这些活全干了。所以现在做国产化替代、做物联网网关、做工业控制器的人很大比例都选它。为什么选Linux 4.19并不是说新内核不好而是瑞芯微对RK3568的官方BSP树主流就是基于4.19这个LTS版本维护的。在这个分支上Mali GPU驱动、VPU编解码、NPU运行时库、ISP相关代码都是配套验证过的。你随便拉一个mainline 5.15或者6.1虽然能启动但很多多媒体、ISP、NPU的驱动你可能要自己补工作量直接翻倍。做产品追求的是稳定和可控官方SDK内核版本反而是最省力的起点。1.2 手动构建内核镜像的适用场景可能有人会问SDK不是有现成脚本一键编译固件吗为什么还要手动构建我自己的体会是一键脚本在你不需要改任何东西的时候很好用但一旦你进了这些场景手动的优势就出来了客户定制了硬件GPIO复用、外设型号、屏幕模组和公版完全不同必须改设备树你要裁剪内核去掉不需要的驱动和框架把镜像体积压下来你要打实时补丁比如配IGH跑EtherCAT主站或者调低中断延迟你要在CI流程里按自己的方式管理内核配置和版本替代SDK的黑盒脚本。手动构建不是说不用SDK的源码而是自己掌握了“源码 → 配置 → 编译 → 打包 → 烧写”这一整条链路。这个链路一旦打通遇到问题你能直接在代码层面定位而不是回到“重新跑一遍build.sh然后烧整包固件”的原始循环里。1.3 环境准备交叉编译工具链与目录规划先交代我这边的环境Ubuntu 20.04 x86_64内核源码用的Rockchip Linux SDK解压出来的kernel目录工具链用的SDK自带的。export ARCHarm64 export CROSS_COMPILEaarch64-linux-gnu- export PATH/opt/gcc-arm-10.3-x86_64-aarch64-none-linux-gnu/bin:$PATH如果没有SDK里的工具链自己用发行版也完全可行sudo apt install gcc-aarch64-linux-gnu之后把交叉编译前缀指到aarch64-linux-gnu-就可以了。这里有个小建议如果计划长期在这个平台开发不要用发行版的gcc和SDK自带的gcc混着编驱动模块编译内核用同一套工具链否则偶尔会遇到一些奇怪的ABI或内联汇编问题排查起来非常隐性。目录层面我习惯把SDK源码和输出分开比如建一个rk3568_build/out/专门放编译产物避免源码目录被一堆中间文件占满也方便后续打包脚本直接引用。如果你用SDK自带脚本那就按SDK的规矩来手动构建时自己规划好路径会更顺手。2. 内核源码获取与配置选对defconfig是成功的一半2.1 源码分支怎么选RK3568的Linux 4.19源码在Rockchip GitHub上维护得比较完整通常是一个类似linux-4.19-rockchip的分支。如果你拿到的是正点原子或者其它开发板的SDK里面kernel目录本身就是一棵完整的内核树直接取用即可。不同厂家的SDK会往里面塞自己的板级dts、驱动和后置补丁所以我不建议上来就换主干先用手头BSP的kernel目录跑通一遍再决定要不要升级分支。一个比较稳妥的做法是先把当前SDK的kernel目录打一个tag或备份之后做的所有修改都基于这个已知可启动的基线。这样出了问题你可以随时diff回退不至于改乱了连个参考坐标都没有。2.2 内核配置管理rockchip_linux_defconfig与配置片段拿到内核源码后配置入口一般不是defconfig这个通用文件而是arch/arm64/configs下面的具体defconfig。我这边用的主要是rockchip_linux_defconfig有的SDK则是rk3568_defconfig或者厂商自定义名称以你手里的源码为准cd kernel make rockchip_linux_defconfig这个defconfig会把RK3568平台上常用外设、文件系统、网络、多媒体相关的配置都打开基本能保证你改完设备树重启后外设正常工作。但要注意defconfig只是“基础套餐”它不等于“你这个硬件的完整配置”。比如某些SDK里摄像头ISP相关驱动、EtherCAT需要的实时抢占配置可能默认没开需要后续手动处理。我的习惯是不直接改defconfig文件而是用内核的配置片段fragment机制管理。举个例子我在目录里放一个rk3568_ethercat.cfg内容包含CONFIG_PREEMPT_RTy CONFIG_HZ_1000y CONFIG_HIGH_RES_TIMERSy CONFIG_POSIX_TIMERSy编译的时候先合并再生成.configmake rockchip_linux_defconfig ./scripts/kconfig/merge_config.sh -m .config rk3568_ethercat.cfg make olddefconfig这样内核基础配置保持统一不同产品线可以各自叠加自己的小配置可读性和可维护性都强很多。2.3 menuconfig必查项实时抢占、文件系统与驱动配置阶段我每次都会进menuconfig核对几个关键项make menuconfig第一个必看的是Kernel Features → Preemption Model。默认一般是Voluntary Kernel Preemption如果你后面要跑EtherCAT或者任何对实时性有要求的应用至少要选到Preemptible Kernel (Low-Latency Desktop)。要真正跑IGH这类工业主站强烈建议打上PREEMPT_RT补丁然后在这一项里选择Fully Preemptible Kernel (Real-Time)。第二个必看的是Filesystem取决于根文件系统是什么。如果你用Buildroot或Debian的ext4根文件系统确认Ext4、Ext3、ext2那堆选项都在如果你用NFS挂载根文件系统调试还要打开Network File Systems里的Root file system on NFS。这个忘了开折腾半天发现内核起来后挂不上根特别浪费时间。第三个是设备驱动里的具体外设。RK3568上最常见的像GMAC网卡、Mali GPU、VPU、NPU一般都在defconfig里开好了但I2C触摸屏驱动、OV5695/OV8858摄像头驱动、特定PHY芯片驱动往往需要自己去Device Drivers里翻。我的建议是配置阶段不要偷懒先记一下硬件bom表然后对照menuconfig逐个确认缺了及时补上否则设备树写得再对驱动没编进去也是白搭。3. 设备树改写把硬件资源画清楚3.1 设备树文件和编译流程设备树在RK3568的Linux开发里通俗点说就是给内核递一张“硬件接线图”。内核本身不关心你的板子的GPIO是怎么接的、PHY地址是几、触摸IC挂在I2C几上这些全部由设备树告诉它。RK3568的设备树文件组织分三层rk3568.dtsi芯片级定义描述芯片内部所有控制器、中断、时钟、pinctrl原则上不要改rk3568-xxx.dtsiSoC板级公共定义比如DDR类型、公共电源域某个具体板级的.dts比如rk3568-evb.dts你这个板子的最终差异全部在这里体现。编译设备树在源码根目录执行make dtbs生成的dtb位于arch/arm64/boot/dts/rockchip/rk3568-你的板子.dtb。如果你改了dts之后单独编译内核内核本身不一定会重新编译但dtb是增量生成的不需要重新make整个内核。这点在迭代调设备树时非常香。3.2 读懂RK3568 dtsi的关键节点打开rk3568.dtsi不要被几千行吓到我们实际改的时候主要关心这几类节点uart2这类串口节点确认status okay并检查pinctrl的tx/rx脚是不是跟你硬件一致i2c0到i2c6挂触摸、摄像头、eeprom、PMIC等外设的入口gmac0和gmac1双千兆网口PHY模式、复位引脚都在这配sdhci、emmcSD卡和eMMC控制器pinctrl全局引脚复用配置所有GPIO功能的最终裁决地dmc、cpu0等调频调压相关性能优化时用得到。这里我特别想提一下pinctrl。RK3568的引脚复用非常灵活一个引脚往往有GPIO、UART、I2C、SPI、PWM等多种功能彼此靠rockchip,pins bank pin func pcfg_xxx决定。出问题的时候绝大多数都是两个节点同时引用了同一个引脚导致pinctrl申请冲突内核日志里会报类似pin 83 already requested的信息这个后面排查章节再细说。3.3 高频改造场景串口、网口PHY和触摸屏刚开始改设备树三个场景遇到得最多调调试串口、配PHY芯片、改触摸屏方向。调试串口的问题很多时候是波特率。RK3568平台调试串口默认通常是ttyS2波特率1500000。你拿到一块定制的板子如果串口打印乱码或者没输出先看两个东西一是内核启动参数里consolettyS2,1500000是否正确二是dts里uart2的status和pinctrl是否打开。两者缺一不可。PHY芯片的配置逻辑稍微绕一点。以YT8521这类国产PHY为例在GMAC节点下面有一个mdio子节点PHY挂在mdio总线上用address来标识。除了reg 0之外还要注意phy-mode的选择rgmiiMAC和PHY都不额外加延迟延迟通过其它方式配置rgmii-idPHY芯片自动处理RX/TX延迟这种写法适配最省心rmii如果你的硬件是RMII接口模式必须对应否则千兆网口直接起不来。触摸屏方向问题后面单独开一节讲因为这里牵扯到显示和输入两头不是只改一个坐标映射属性就结束。4. 构建内核镜像从Image到可烧写的boot.img4.1 编译命令与产物说明配置完成后编译内核本体很简单make -j$(nproc) Image dtbs其中Image是未压缩的arm64内核镜像位于arch/arm64/boot/Imagedtbs会把你代码里所有使能的dts全部编成dtb。如果只需要某一个板子make -j$(nproc) Image make rockchip/rk3568-我的板子.dtb内核模块按需编译make -j$(nproc) modules编出来的Image可以直接被U-Boot加载但实际烧写时不能只烧一个Image因为U-Boot需要一个结构完整的boot镜像。这就是Rockchip平台和树莓派之类平台最大的区别你的镜像要按boot.img格式封装。4.2 打包boot.img与resource.img瑞芯微的boot.img本质是一段头部信息 kernel镜像 dtb资源段 ramdisk的组合。SDK里通常有打包脚本我推荐优先用官方脚本但自己理解一遍打包过程还是很有必要的不然遇到脚本挂掉你都不知道缺了什么。一个通用的手动打包思路如下# 生成resource.img把dtb打包进去 ./resource_tool --dtbnamerk3568-我的板子.dtb # 生成boot.img包含kernel和resource mkbootimg --kernel arch/arm64/boot/Image \ --ramdisk ramdisk.img \ --resource resource.img \ -o boot.img不同SDK版本的resource_tool和mkbootimg路径可能不一样但这套逻辑在RK3568的Linux SDK里是通用的。如果你的SDK是比较新的版本可能已经不再单独使用resource分区而是把dtb直接合入boot.img这时候你只要执行./build.sh bootimg它会自动完成Image、dtb、ramdisk的组装生成可烧写的boot.img。我第一次接触的时候在打包环节卡了一晚上最后发现卡在ramdisk路径上SDK默认生成的ramdisk和内核dtb不在同一层目录脚本找不到文件就直接报错退出。所以建议你先跑通一次官方脚本让它把所有中间产物路径都打印出来再决定要不要自己接管打包逻辑。4.3 烧写流程与启动参数验证boot.img打包好之后烧写方式取决于根文件系统方案。如果你用eMMC启动常见做法是进入Loader模式用瑞芯微的upgrade_tool或者Windows下的RKDevTool烧写upgrade_tool di -b boot.img如果只是临时调试也可以用U-Boot的ums或者fastboot把boot分区挂出来直接dd覆盖dd if/boot.img of/dev/block/bootloader注意具体分区名要看parameter.txt不同SDK的分区表不一样不要想当然写死。烧完之后建议先验证内核启动参数和设备树加载情况串口能看到Starting kernel ...说明U-Boot已经把镜像传给内核了内核启动早期日志能看到Kernel command line: ...确认console、root参数对不对设备树加载成功后dmesg | grep machine会显示你dts里定义的model。如果这三步都正常那么内核镜像这条链路基本算是通了后面所有优化都建立在这个可启动系统之上。5. 设备树优化实战EtherCAT、摄像头和显示方向5.1 对EtherCAT/IGH主站的实时性优化RK3568跑工业控制最典型的需求就是EtherCAT。热词里提到“适配rk3568的ethercat i gh主站驱动”说明不少人在这条路上踩过坑。EtherCAT主站对实时性非常敏感它的运行周期一般从250us到1ms要求内核调度抖动足够小。第一步是给内核打上PREEMPT_RT补丁。Linux 4.19对应的RT补丁版本要和你内核版本完全匹配否则打不上或者编出来的内核不稳定。补丁打好之后内核配置里选到Fully Preemptible Kernel (Real-Time)同时建议把CONFIG_HZ_1000打开让时钟中断分辨率更高。第二步是设备树层面的配合。网卡中断的亲和性最好绑定到一个独立CPU核上避免网卡中断和EtherCAT主站任务互相干扰。虽然中断亲和性可以在运行时通过/proc/irq/xxx/smp_affinity_list调但如果你想让每次启动都自动化可以写一个小的systemd服务在启动时设置先cat /proc/interrupts | grep eth0找到中断号然后把亲和性写到那个CPU核上。第三步是关闭CPU调频调压的干扰。实时任务运行期间CPU频率跳变会造成明显的执行时间抖动。如果不需要动态调频可以在设备树里把cpu0等节点的cpu-supply和operating-points调整一下或者运行时把governor固定为performancecpupower frequency-set -g performance我个人经验是PREEMPT_RT 1000Hz CPU固定performance 中断亲和性绑定这四步做完RK3568上跑IGH主站1ms周期的抖动可以控制在几十微秒级别250us周期需要更细致的调优但作为入门配置已经够用了。5.2 摄像头OV5695/OV8858接入的DTS要点RK3568这颗芯片在视觉方向用得非常广很多项目会挂OV5695或者OV8858做图像采集。摄像头接入设备树的坑主要在电源、时钟、复位时序这三块。以OV5695为例I2C挂在某个i2c总线上主节点长这样i2c3 { status okay; ov5695: ov569536 { compatible ovti,ov5695; reg 0x36; clocks cru CLK_MIPICAM_OUT; clock-names xvclk; pinctrl-names default; pinctrl-0 ov5695_rst; reset-gpios gpio3 RK_PB1 GPIO_ACTIVE_LOW; pwdn-gpios gpio3 RK_PB0 GPIO_ACTIVE_HIGH; avdd-supply vcc_avdd; dovdd-supply vcc_dovdd; dvdd-supply vcc_dvdd; rockchip,camera-module-index 0; rockchip,camera-module-facing back; rockchip,camera-module-name default; rockchip,camera-module-lens-name default; port { ov5695_out: endpoint { remote-endpoint csi2_dphy0_input; >