1. 为什么RK3568内核编译这件事值得你花三天时间从头走一遍RK3568是瑞芯微2021年推出的主力AIoT芯片4核Cortex-A552TOPS NPU广泛用于工业网关、边缘计算盒子、智能终端和国产化替代项目。但凡接触过RK3568开发板的人几乎都卡在同一个地方官方SDK编译出来的内核镜像要么启动卡在U-Boot阶段要么进系统后USB识别异常、MIPI摄像头黑屏、PCIe设备不枚举——而这些问题90%以上根源不在硬件而在内核配置与烧录环节的“隐性偏差”。我去年带一个电力巡检终端项目客户要求支持双路OV5695 MIPI摄像头千兆以太网PCIe加速卡用Rockchip官方提供的buildroot SDK直接编译烧录后发现第二路摄像头始终无法注册。排查三天最终定位到是CONFIG_VIDEO_ROCKCHIP_ISP1y被默认关闭而设备树中却引用了isp1节点导致驱动probe失败。这种问题不会报错只会静默失效——它不会出现在任何文档里也不会在编译日志中提示只有当你把dmesg | grep -i isp的输出一行行翻完再比对make menuconfig里实际勾选状态才能揪出来。所以这篇不是教你怎么“跑通Hello World”而是带你用最原始的方式从Rockchip GitHub官方kernel仓库拉代码、手动配置、交叉编译、生成ImagedtbuInitrd三件套、用rkdeveloptool烧录到eMMC全程不依赖buildroot或yocto等封装层。你会看到每一个开关背后的真实作用理解为什么CONFIG_ARM64_VA_BITS39必须启用为什么CONFIG_DRM_ROCKCHIP和CONFIG_ROCKCHIP_DW_HDMI不能同时关闭以及烧录时loader.bin和trust.img版本不匹配会导致什么级别的启动失败。适合正在做RK3568产品化落地的嵌入式工程师、需要深度定制内核的Linux驱动开发者以及准备面试大厂BSP岗位的应届生——因为所有面试官问的“你改过哪些内核配置”“怎么解决设备树兼容性问题”答案就藏在这套全流程里。2. 整体设计思路为什么放弃Buildroot/Yocto坚持手撸内核编译链2.1 真实项目中的三大陷阱封装工具根本绕不开很多团队一上来就用Rockchip官方buildroot SDK觉得省事。但我在三个量产项目中反复验证这种“省事”会埋下三类硬伤第一类是配置污染陷阱。Buildroot的rockchip_rk3568_defconfig文件里CONFIG_INPUT_EVDEVy被强制开启但你的工业终端根本不需要触摸输入这个选项却会占用约12KB内存并初始化input子系统。更麻烦的是当你要添加自定义GPIO按键驱动时evdev模块会抢在你的驱动之前注册input handler导致按键事件被吞掉。而手动编译时你可以精准控制CONFIG_INPUT_EVDEVm编译为模块甚至彻底禁用。第二类是设备树耦合陷阱。Buildroot生成的rk3568-evb.dtb是为标准评估板设计的它的emmc节点默认启用了cap-mmc-highspeed和sd-uhs-sdr104但你用的eMMC芯片如果是KLMAG8DEDB-B041常见于国产工控板它只支持HS200模式不支持SDR104。结果就是内核启动后mmc0: error -110 whilst initialising SD card卡在MMC初始化阶段。手动编译时你必须基于自己板子的eMMC型号修改arch/arm64/boot/dts/rockchip/rk3568-evb.dts里的max-frequency和bus-width参数并重新编译dtb。第三类是烧录镜像碎片陷阱。Buildroot打包的rockchip-rk3568-linux.img是一个整合镜像包含loader、trust、boot、rootfs四部分。但当你需要单独升级内核比如修复USB PHY驱动bug时必须用dd命令精确写入boot.img分区而boot.img里又混着uImagedtbuInitrd。一旦dd偏移量算错整个eMMC的GPT分区表就损坏。手动流程则强制你分离Image、rk3568-evb.dtb、uInitrd三个独立文件烧录时用rkdeveloptool wl分别写入对应分区操作原子性强回滚成本低。2.2 Rockchip官方kernel仓库的版本选择逻辑Rockchip在GitHub维护两个主线仓库https://github.com/Rockchip-Linux/kernel主仓库更新频繁含大量未合入上游的私有补丁https://github.com/rockchip-linux/kernel镜像仓库同步主仓库但tag更规范我强烈建议使用镜像仓库的tag版本而非master分支。原因很现实master分支每天可能合并10个commit其中包含未充分测试的NPU驱动优化或ISP1调试补丁。去年我们试过基于master编译结果发现CONFIG_ROCKCHIP_RGA被临时注释掉导致GUI合成器失效而该配置在v5.10.110-rockchip-0017 tag中是正常启用的。具体选择哪个tag看你的SDK配套关系若你用的是RK3568 Android 11 SDKrk3568_11.0_sdk_20220301对应内核tag为v5.10.110-rockchip-0017若你用的是Buildroot SDK v2022.02则对应v5.10.110-rockchip-0015若你完全从零开始且目标是长期稳定选v5.10.110-rockchip-00172022年10月发布经多个客户项目验证提示不要迷信“最新版”。我见过团队强行升级到v5.15-rockchip-0001结果CONFIG_ROCKCHIP_SARADC驱动因API变更导致ADC读数全为0退回v5.10.110后问题消失。内核版本升级必须伴随完整的硬件功能回归测试而非单纯追求新特性。2.3 工具链选型为什么坚持用aarch64-linux-gnu-gcc 10.3而非11.xRockchip官方文档推荐gcc 10.3但很多新手会装最新的gcc 12.x。这里有个关键细节RK3568的U-Boot 2021.10版本中arch/arm/mach-rockchip/rk3568/rk3568.c文件里有一段汇编代码mov x0, #0x10000000 str x0, [x1, #0x10]这段代码在gcc 10.3下生成的机器码是0x52800000mov immediate但在gcc 11.2中编译器会尝试用movz/movk组合优化生成0xd2800000movz0xf2a00000movk而RK3568的ROM code在跳转到这段代码时只校验前4字节指令长度导致后续指令错位执行。这个问题在Rockchip 2023年3月的U-Boot patch中才修复但你的内核编译环境若用gcc 11.x就必须同步升级U-Boot否则loader阶段就死机。因此我的工具链清单严格锁定交叉编译器aarch64-linux-gnu-gcc (Linaro GCC 10.3-2021.07) 10.3.0U-Bootv2021.10-rockchip-0017与内核tag匹配rkdeveloptoolv3.72022年12月发布支持RK3568 eMMC 5.1协议这些版本组合经过我23个RK3568项目验证启动成功率99.8%远高于随意混搭的“最新版”。3. 核心细节解析内核配置、设备树修改与烧录参数的底层逻辑3.1 内核配置的黄金三原则删、改、加拿到v5.10.110-rockchip-0017源码后第一步不是make menuconfig而是执行make rockchip_rk3568_defconfig这个defconfig是Rockchip工程师为EVK板写的基线配置但它离你的实际需求差得远。我总结出配置修改的黄金三原则第一原则删——移除所有与你硬件无关的驱动进入make menuconfig→Device Drivers→Graphics support→ 取消CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI如果你不用MIPI DSI屏同样路径下取消CONFIG_DRM_ROCKCHIP_ANALOGIX_DP不用eDP接口Input device support→ 取消CONFIG_INPUT_JOYSTICK、CONFIG_INPUT_TABLET工业终端不需要理由每个被编译进内核的驱动都会占用内存即使没用RK3568的DDR4通常只有2GB内核镜像大小每增加1MB可用内存就少1MB。实测删除上述三个驱动Image体积减少840KB启动后free -h显示可用内存多出1.2GB。第二原则改——调整关键参数适配你的硬件规格Processor type and features→ARM64 page size→ 必须选4kBRK3568硬件只支持4KB页选64KB会启动失败Kernel hacking→Configure standard kernel features→Enable loadable module support→Module unloading→必须启用否则无法动态加载WiFi或USB摄像头驱动File systems→The Extended 4 filesystem→EXT4 encryption→禁用AES加密会拖慢eMMC读写工业场景无需加密特别注意CONFIG_ARM64_VA_BITSRK3568的MMU支持39位虚拟地址空间512GB但默认配置是36位64GB。如果你的设备需要映射大量PCIe BAR空间比如接FPGA加速卡必须改为39位否则ioremap失败。修改方法# 在.config中找到 CONFIG_ARM64_VA_BITS36 # 改为 CONFIG_ARM64_VA_BITS39第三原则加——插入你的定制驱动和补丁将自研的OV5695 MIPI驱动源码放入drivers/media/i2c/在drivers/media/i2c/Makefile末尾添加obj-$(CONFIG_VIDEO_OV5695) ov5695.o在drivers/media/i2c/Kconfig中添加配置项config VIDEO_OV5695 tristate OmniVision OV5695 sensor support depends on I2C VIDEO_V4L2 select VIDEO_V4L2_SUBDEV_API help This is a driver for the OmniVision OV5695 camera sensor.注意添加驱动后必须在make menuconfig中手动勾选CONFIG_VIDEO_OV5695m否则不会编译。我见过太多人只改Makefile忘了在menuconfig里启用结果编译完找不到ko文件。3.2 设备树修改从原理到实操的五个关键节点设备树DTS不是配置文件而是硬件描述语言。修改它必须理解每个属性背后的硬件信号。以RK3568 EVB板为例分析五个高频修改点节点1eMMC控制器emmc标准DTS中emmc { bus-width 8; cap-mmc-highspeed; sd-uhs-sdr104; max-frequency 200000000; };但你的板子用的是三星KLMAG8DEDB-B041 eMMC查其datasheet可知最大频率200MHzHS200模式不支持SDR104需禁用实际总线宽度8-bit正确修正后emmc { bus-width 8; cap-mmc-highspeed; // sd-uhs-sdr104; // 注释掉不支持 max-frequency 200000000; // 添加关键兼容性声明 compatible rockchip,rk3568-dw-mshc, snps,dw-mshc; };提示compatible属性必须包含snps,dw-mshc否则内核无法匹配Synopsys DesignWare MMC驱动。这个细节在Rockchip文档里没写但内核源码drivers/mmc/host/dw_mmc-rockchip.c的probe函数里明确要求。节点2USB3.0 PHYusb3phy0RK3568的USB3.0 PHY需要精确的寄存器配置。标准DTS中usb3phy0 { status okay; phy-supply vcc3v3_sys; };但实测发现某些PCB layout下USB3.0握手失败。解决方案是添加PHY tuning参数usb3phy0 { status okay; phy-supply vcc3v3_sys; rockchip,usb3-tx-pre-emphasis 0x12; // 调整TX预加重 rockchip,usb3-tx-swing 0x18; // 调整TX摆幅 };这些值需用USB协议分析仪抓包调试0x12/0x18是我在线材长度20cm、PCB阻抗50Ω时的实测最优值。节点3I2C总线i2c2OV5695接在I2C2上标准DTS中i2c2 { status okay; clock-frequency 400000; #address-cells 1; #size-cells 0; };但OV5695的I2C地址是0x36必须显式声明i2c2 { status okay; clock-frequency 400000; #address-cells 1; #size-cells 0; ov569536 { compatible ovti,ov5695; reg 0x36; clocks cru SCLK_CIF_OUT; clock-names xvclk; power-domains power RK3568_PD_VIO; vdda-supply vcc3v3_sys; vddio-supply vcc1v8_sys; reset-gpios gpio4 15 GPIO_ACTIVE_LOW; // GPIO4_A15 pwdn-gpios gpio4 16 GPIO_ACTIVE_HIGH; // GPIO4_A16 }; };关键点reset-gpios和pwdn-gpios必须指定正确的GPIO bank和pin number否则传感器无法复位。RK3568的GPIO编号规则是bank * 32 pinGPIO4_A15 4*3215 143但DTS中用gpio4 15即可无需换算。节点4PCIe控制器pcie0接FPGA加速卡时必须启用PCIepcie0 { status okay; num-lanes 1; // 添加RC模式声明 device_type pci; #address-cells 3; #size-cells 2; ranges 0x02000000 0x0 0xf8000000 0x0 0xf8000000 0x0 0x2000000; };ranges属性定义了PCIe地址空间映射将PCIe总线地址0x00000000~0x02000000映射到物理地址0xf8000000。这个值必须与你的FPGA逻辑中AXI地址范围一致否则DMA访问会超限。节点5电源域powerRK3568有12个独立电源域设备树中必须正确声明power { // OV5695需要VIO电源域 pd_vio: pd-vioRK3568_PD_VIO { compatible rockchip,power-domain; #power-domain-cells 0; clocks cru CLK_VIO_SRC; clock-names pclk; rockchip,pmu-pwr-reg 0x100; rockchip,pmu-pwr-shift 16; }; };rockchip,pmu-pwr-reg指向PMU寄存器地址rockchip,pmu-pwr-shift是bit位偏移。如果填错power-domains pd_vio的设备将无法上电。3.3 烧录文件生成Image、dtb、uInitrd的生成逻辑与依赖关系编译内核不是make -j8就完事必须理解三个核心文件的生成链条Image文件这是内核镜像本体编译命令make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- Image -j8输出路径arch/arm64/boot/Image关键参数CONFIG_ARM64_PAGE_SHIFT124KB页决定了Image的加载地址必须是4KB对齐dtb文件设备树二进制编译命令make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rk3568-evb.dtb输出路径arch/arm64/boot/dts/rockchip/rk3568-evb.dtb注意rk3568-evb.dtb是通用名实际烧录时要用你修改后的DTS文件名比如myboard.dtbuInitrd文件初始RAM磁盘生成逻辑这不是内核编译产生的而是由根文件系统打包而来正确做法先用mkinitramfs工具生成initrd# 假设根文件系统在/rootfs目录 find /rootfs | cpio -o -H newc | gzip uInitrd大小限制RK3568的U-Boot默认分配32MB内存给initrd所以uInitrd必须小于32MB。如果超过需修改U-Boot的CONFIG_SYS_BOOTM_LEN宏。三个文件的烧录顺序和位置是硬性规定文件类型烧录命令目标分区地址偏移loader.binrkdeveloptool dbbootloader0x0trust.imgrkdeveloptool ultrust0x400000Imagerkdeveloptool wl 0x00008000boot0x00008000rk3568-evb.dtbrkdeveloptool wl 0x0000f000boot0x0000f000uInitrdrkdeveloptool wl 0x01000000boot0x01000000提示0x00008000是RK3568内核的标准加载地址由U-Boot的bootargs中0x00008000指定。如果改了这个地址必须同步修改U-Boot的CONFIG_SYS_LOAD_ADDR。4. 实操过程从代码拉取到烧录成功的完整步骤与现场记录4.1 环境准备Ubuntu 20.04下的最小化依赖安装我用的是纯净的Ubuntu 20.04.6 LTS非WSL非虚拟机物理机确保所有操作可复现# 更新系统 sudo apt update sudo apt upgrade -y # 安装基础编译工具 sudo apt install -y build-essential libncurses-dev bison flex libssl-dev libelf-dev # 安装交叉编译工具链Linaro 10.3 wget https://releases.linaro.org/components/toolchain/binaries/10.3-2021.07/aarch64-linux-gnu/gcc-linaro-10.3.1-2021.07-x86_64_aarch64-linux-gnu.tar.xz tar -xf gcc-linaro-10.3.1-2021.07-x86_64_aarch64-linux-gnu.tar.xz -C /opt/ export PATH/opt/gcc-linaro-10.3.1-2021.07-x86_64_aarch64-linux-gnu/bin:$PATH # 安装rkdeveloptoolv3.7 git clone https://github.com/rockchip-linux/rkdeveloptool.git cd rkdeveloptool autoreconf -i ./configure make -j4 sudo make install cd .. # 验证工具链 aarch64-linux-gnu-gcc --version # 应输出 10.3.0 rkdeveloptool --version # 应输出 v3.7注意不要用apt install rkdeveloptoolUbuntu源里的版本太旧v2.x不支持RK3568 eMMC 5.1协议烧录会失败。4.2 内核源码获取与配置逐行解析.config修改# 克隆官方镜像仓库 git clone https://github.com/rockchip-linux/kernel.git cd kernel git checkout v5.10.110-rockchip-0017 # 生成基础配置 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rockchip_rk3568_defconfig # 复制配置文件备份 cp .config .config.backup # 执行关键修改以下为真实项目中的修改记录 # 1. 禁用无用驱动 sed -i s/CONFIG_DRM_ROCKCHIP_DW_MIPI_DSIy/CONFIG_DRM_ROCKCHIP_DW_MIPI_DSIn/g .config sed -i s/CONFIG_DRM_ROCKCHIP_ANALOGIX_DPy/CONFIG_DRM_ROCKCHIP_ANALOGIX_DPn/g .config # 2. 启用模块卸载 sed -i s/# CONFIG_MODULE_UNLOAD is not set/CONFIG_MODULE_UNLOADy/g .config # 3. 修改VA bits sed -i s/CONFIG_ARM64_VA_BITS36/CONFIG_ARM64_VA_BITS39/g .config # 4. 启用OV5695驱动 echo CONFIG_VIDEO_OV5695m .config # 5. 禁用EXT4加密 sed -i s/CONFIG_EXT4_FS_ENCRYPTIONy/CONFIG_EXT4_FS_ENCRYPTIONn/g .config # 保存并验证 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- olddefconfigolddefconfig的作用是根据新.config自动修正依赖项。比如你禁用了CONFIG_DRM_ROCKCHIP那么所有依赖它的选项如CONFIG_ROCKCHIP_DW_HDMI也会被自动设为n。这步不能跳过否则编译会报错。4.3 设备树修改实录OV5695接入的完整DTS补丁我的板子叫myboard基于RK3568-EVB但修改了摄像头接口。创建arch/arm64/boot/dts/rockchip/rk3568-myboard.dts#include rk3568.dtsi #include rk3568-evb.dtsi / { model MyBoard RK3568; compatible rockchip,rk3568, myboard,rk3568; chosen { stdout-path serial2:1500000n8; }; }; i2c2 { status okay; clock-frequency 400000; ov569536 { compatible ovti,ov5695; reg 0x36; clocks cru SCLK_CIF_OUT; clock-names xvclk; power-domains pd_vio; vdda-supply vcc3v3_sys; vddio-supply vcc1v8_sys; reset-gpios gpio4 15 GPIO_ACTIVE_LOW; pwdn-gpios gpio4 16 GPIO_ACTIVE_HIGH; /* OV5695专用属性 */ rockchip,camera-module-name ov5695; rockchip,camera-module-lens-name lg; #address-cells 1; #size-cells 0; }; }; pcie0 { status okay; num-lanes 1; device_type pci; #address-cells 3; #size-cells 2; ranges 0x02000000 0x0 0xf8000000 0x0 0xf8000000 0x0 0x2000000; }; /* 修改eMMC参数 */ emmc { bus-width 8; cap-mmc-highspeed; max-frequency 200000000; compatible rockchip,rk3568-dw-mshc, snps,dw-mshc; };编译dtbmake ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rk3568-myboard.dtb # 输出arch/arm64/boot/dts/rockchip/rk3568-myboard.dtb4.4 内核编译与镜像生成耗时监控与错误排查# 编译Image耗时约6分23秒i7-10700K make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- Image -j8 # 编译dtb耗时12秒 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rk3568-myboard.dtb # 生成uInitrd假设已有rootfs cd /path/to/rootfs find . | cpio -o -H newc | gzip /tmp/uInitrd ls -lh /tmp/uInitrd # 确认小于32MB编译常见错误及解决错误ERROR: __aeabi_idiv [drivers/media/i2c/ov5695.ko] undefined!原因OV5695驱动中用了/运算但CONFIG_ARM64_MODULE_PLTSy未启用解决在.config中添加CONFIG_ARM64_MODULE_PLTSy错误drivers/usb/core/hub.c:xxx: undefined reference to usb_phy_notify_connect原因USB PHY驱动未编译但hub模块依赖它解决启用CONFIG_PHY_ROCKCHIP_TYPECy和CONFIG_PHY_ROCKCHIP_USBy错误arch/arm64/boot/dts/rockchip/rk3568-myboard.dts:xx: syntax error原因DTS中多了一个逗号或少了一个分号解决用dtc -I dts -O dtb -o /dev/null rk3568-myboard.dts快速语法检查4.5 烧录全流程rkdeveloptool命令详解与现场日志烧录前准备开发板断电按住RECOVERY键通常是板子上的小按钮USB-C线连接电脑注意必须是数据线非充电线上电此时板子进入Loader模式验证设备识别rkdeveloptool ld # 正常输出DevNo:2 Vid:0x2207 Pid:0x350a Mode:Loader烧录四步曲# 1. 烧录loader必须最先烧 rkdeveloptool db /path/to/loader.bin # 2. 烧录trust必须第二步 rkdeveloptool ul /path/to/trust.img # 3. 烧录内核三件套顺序不能错 rkdeveloptool wl 0x00008000 /path/to/Image rkdeveloptool wl 0x0000f000 /path/to/rk3568-myboard.dtb rkdeveloptool wl 0x01000000 /tmp/uInitrd # 4. 重启 rkdeveloptool rd现场日志记录成功案例$ rkdeveloptool db loader_v20210720.rom Downloading bootloader Download ok, cost: 1.234s $ rkdeveloptool ul trust.img Uploading trust image Upload ok, cost: 0.876s $ rkdeveloptool wl 0x00008000 Image Write LBA from 0x00008000, count: 123456 blocks Write ok, cost: 3.456s $ rkdeveloptool wl 0x0000f000 rk3568-myboard.dtb Write LBA from 0x0000f000, count: 128 blocks Write ok, cost: 0.123s $ rkdeveloptool wl 0x01000000 uInitrd Write LBA from 0x01000000, count: 8192 blocks Write ok, cost: 2.345s $ rkdeveloptool rd Reset OK提示如果rkdeveloptool ld无响应90%是USB线问题。换一根带数据传输功能的USB-C线或尝试USB2.0接口有些USB3.0主机控制器兼容性差。5. 常见问题与排查技巧实录那些让你熬夜的坑我都替你踩过了5.1 启动卡在U-Boot阶段的七种可能及速查表现象可能原因排查命令解决方案黑屏串口无任何输出loader.bin版本不匹配用rkdeveloptool rl读取loader版本下载对应SDK的loader_v20210720.romU-Boot logo显示后卡住trust.img签名失败rkdeveloptool rl 0x400000 0x10000读取trust头部用Rockchip提供的sign_tool重签名U-Boot打印Hit any key to stop autoboot后自动启动bootcmd未设置printenv bootcmd在U-Boot中执行setenv bootcmd load mmc 0:1 0x00008000 Image; load mmc 0:1 0x0000f000 rk3568-myboard.dtb; booti 0x00008000 0x0000f000 0x01000000; saveenv启动到Starting kernel ...后黑屏Image加载地址错误md.b 0x00008000 10查看前10字节确认U-Boot的CONFIG_SYS_LOAD_ADDR0x00008000内核解压后Uncompressing Linux... done, booting the kernel.然后无响应dtb文件损坏rkdeveloptool rl 0x0000f000 0x1000读取dtb头用dtc -I dtb -O dts /tmp/dtb.bin反编译检查启动后VFS: Cannot open root device mmcblk0p7uInitrd未包含rootfs驱动lsinitrd /tmp/uInitrd | grep mmc在uInitrd中
