1. RK3568 Linux驱动开发环境搭建

第一次接触RK3568驱动开发时,我被官方SDK的庞大规模震撼到了——整整35GB的源码包!不过别担心,跟着我的步骤走,30分钟就能搞定基础环境。我用的是一台16核32G内存的Ubuntu 20.04主机,实测8G内存的虚拟机也能跑,但编译时间会翻倍。

核心依赖安装是第一步,这个命令集合了瑞芯微官方推荐和我的经验补充:

sudo apt-get install -y git ssh make gcc libssl-dev liblz4-tool expect \
g++ patchelf chrpath gawk texinfo diffstat binfmt-support \
qemu-user-static live-build bison flex fakeroot cmake \
unzip device-tree-compiler python3-pip libncurses-dev

特别注意Python版本问题:RK3568 SDK对Python2.7有强依赖,但Ubuntu 20.04默认只有Python3。我的解决方案是:

sudo apt-get install python2.7
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1

2. SDK获取与初始化

正点原子提供的SDK压缩包(约15GB)解压后,关键目录结构是这样的:

rk3568_linux_sdk/
├── .repo/          # 多仓库管理元数据
├── buildroot/      # 根文件系统构建
├── device/         # 板级配置文件
├── kernel/         # Linux 4.19内核
├── prebuilts/      # 交叉编译工具链
└── u-boot/         # Bootloader源码

初始化SDK时容易卡在repo sync步骤,这里有个加速技巧:

cd ~/rk3568_linux_sdk
.repo/repo/repo sync -l -j$(nproc) --no-tags

遇到网络中断时,用这个命令续传:

.repo/repo/repo sync -c -j$(nproc) --no-clone-bundle

3. 驱动开发环境配置

交叉编译器配置是驱动开发的关键。SDK自带的工具链路径在:

prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/

建议把工具链加入环境变量:

export PATH=$PATH:~/rk3568_linux_sdk/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
export CROSS_COMPILE=aarch64-linux-gnu-

验证工具链是否生效:

aarch64-linux-gnu-gcc --version
# 应该显示 Linaro GCC 6.3.1

4. 内核模块开发实战

以最简单的LED驱动为例,在kernel/drivers/char/下新建rk_led.c:

#include <linux/module.h>
#include <linux/fs.h>

static int major;
static struct class *led_class;

static int led_open(struct inode *inode, struct file *filp) {
    printk("LED device opened\n");
    return 0;
}

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
};

static int __init led_init(void) {
    major = register_chrdev(0, "rk_led", &led_fops);
    led_class = class_create(THIS_MODULE, "rk_led_class");
    device_create(led_class, NULL, MKDEV(major, 0), NULL, "rk_led");
    return 0;
}

static void __exit led_exit(void) {
    device_destroy(led_class, MKDEV(major, 0));
    class_destroy(led_class);
    unregister_chrdev(major, "rk_led");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

对应的Makefile配置:

obj-$(CONFIG_RK_LED) += rk_led.o

在kernel/drivers/char/Kconfig中添加:

config RK_LED
    tristate "RK3568 LED Driver"
    default y
    help
      Simple LED driver for RK3568

5. 模块编译与加载

内核配置是第一步:

cd ~/rk3568_linux_sdk/kernel
make ARCH=arm64 rockchip_linux_defconfig
make ARCH=arm64 menuconfig

在Character devices中找到我们的驱动选项,按Y键编译进内核,或M键编译为模块。

单独编译模块的命令:

./build.sh kernel
./build.sh modules

编译好的模块会在kernel/drivers/char/rk_led.ko,通过adb推送到开发板:

adb push rk_led.ko /data
adb shell insmod /data/rk_led.ko

查看驱动是否加载成功:

adb shell ls /dev/rk_led
adb shell dmesg | grep LED

6. 驱动调试技巧

printk日志分级很实用,在驱动中添加:

printk(KERN_DEBUG "Debug message\n");  // 级别0
printk(KERN_INFO "Info message\n");    // 级别4
printk(KERN_ERR "Error message\n");    // 级别3

通过adb shell cat /proc/sys/kernel/printk查看当前日志级别,修改级别过滤低优先级信息:

adb shell "echo 4 4 1 7 > /proc/sys/kernel/printk"

Oops分析是驱动开发必备技能。当内核崩溃时,用这个命令保存现场:

adb shell "cat /proc/vmcore > /data/vmcore"

然后用SDK中的工具链分析:

aarch64-linux-gnu-gdb vmlinux
(gdb) core-file vmcore

7. 固件打包与烧写

全编译命令会生成完整固件:

./build.sh all
./mkfirmware.sh

生成的固件在rockdev/目录下,关键文件:

  • MiniLoaderAll.bin:一级loader
  • uboot.img:U-Boot镜像
  • boot.img:内核镜像
  • rootfs.img:根文件系统

使用rkdeveloptool烧写镜像:

rkdeveloptool db MiniLoaderAll.bin
rkdeveloptool ul boot.img
rkdeveloptool ul rootfs.img

遇到烧写失败时,尝试进入MaskROM模式:短接开发板上的测试点,同时上电。

更多推荐