












一、验证环境与最终结果
验证环境:
| 项目 | 配置 |
|---|---|
| SoC | RK3588S2 |
| 开发板 | Radxa ROCK 5C |
| Android | Android 12 / arm64 |
| Linux | 5.10.160 |
| 原 RKNPU | 0.8.8,内建于内核 |
| 目标 RKNPU | 0.9.8,驱动日期 20240828 |
| 构建方式 | Rockchip AOSP BSP + Clang |
| 部署方式 | 设备专用 boot 镜像 + U-Boot Fastboot |
最终设备能够普通重启进入 Android,并报告:
Linux 5.10.160 #57
RKNPU driver: v0.9.8
rknpu 0.9.8 20240828
整个过程只更新了 boot 分区,没有写入其他分区。
先在 Android 设备上读取当前状态:
adb -s <DEVICE> root
adb -s <DEVICE> wait-for-device
adb -s <DEVICE> shell cat /sys/kernel/debug/rknpu/version
adb -s <DEVICE> shell "dmesg | grep -m1 'Initialized rknpu'"
本次设备最初返回:
RKNPU driver: v0.8.8
还需要确认驱动是内建内核还是独立模块:
adb -s <DEVICE> shell \
"zcat /proc/config.gz | grep CONFIG_ROCKCHIP_RKNPU"
结果为:
CONFIG_ROCKCHIP_RKNPU=y
=y 表示 RKNPU 已编进 kernel Image,没有可单独卸载和替换的 .ko。
因此本次升级必须重新编译 kernel,并通过 boot 分区部署。
如果设备没有 /proc/config.gz,可以检查 AOSP 内核最终 .config,或者在
源码配置片段中搜索同一个配置项。
使用与 RKLLM SDK 同版本提供的官方驱动归档:
rknpu-driver/rknpu_driver_0.9.8_20241009.tar.bz2
先校验压缩包:
sha256sum \
<RKNN_LLM_SDK>/rknpu-driver/rknpu_driver_0.9.8_20241009.tar.bz2
本次 SDK 1.3.0 归档的 SHA-256 为:
188306a3eba7ca48c186fe2a39acf232dec8536484581e54e9b96c3f65677eba
不同 SDK 发布版本应以自己的官方文件为准,不要看到文件名相同就跳过校验。
在修改内核前先检查 Git 状态:
cd <AOSP_ROOT>
git -C kernel-5.10 status --short
不要覆盖或清理其他开发者的改动。然后备份当前 RKNPU 0.8.8 源码:
tar -cjf <BACKUP_DIR>/rknpu-before-0.9.8.tar.bz2 \
-C kernel-5.10/drivers rknpu
解压官方归档:
mkdir -p <WORK_DIR>/rknpu-0.9.8
tar -xjf \
<RKNN_LLM_SDK>/rknpu-driver/rknpu_driver_0.9.8_20241009.tar.bz2 \
-C <WORK_DIR>/rknpu-0.9.8
归档中包含完整的 drivers/rknpu。升级时应整体更新驱动目录,而不是只修改
报告版本号的头文件,也不要混用 0.8.8 和 0.9.8 的零散文件。
官方 0.9.8 驱动与当前 Rockchip Android 12 / Linux 5.10 BSP 存在三处
编译接口差异:
MONITOR_TYPE_DEV 在当前 BSP 中拼写为 MONITOR_TPYE_DEV;rockchip_opp_set_low_length 回调不在当前 5.10 OPPvm_flags_set()、vm_flags_clear() 在当前 5.10 BSP 中需要项目提供了最小兼容补丁:
cd <AOSP_ROOT>/kernel-5.10
git apply --check \
<PROJECT_ROOT>/patches/rknpu-0.9.8-android12-linux5.10.patch
git apply \
<PROJECT_ROOT>/patches/rknpu-0.9.8-android12-linux5.10.patch
git diff --check -- drivers/rknpu
补丁只解决编译期 API 差异,没有删除或绕过 RK3588 的 OPP、任务提交和 NPU
执行路径。
本次产品使用:
kernel: kernel-5.10
config: rockchip_defconfig android-11.config rock5c.config
DTS: rk3588s-rock-5c
编译命令:
cd <AOSP_ROOT>
export PATH="$PWD/prebuilts/clang/host/linux-x86/clang-r416183b/bin:$PATH"
make -C kernel-5.10 clean
make -C kernel-5.10 \
CROSS_COMPILE=aarch64-linux-gnu- \
LLVM=1 LLVM_IAS=1 ARCH=arm64 \
rockchip_defconfig android-11.config rock5c.config
make -C kernel-5.10 \
CROSS_COMPILE=aarch64-linux-gnu- \
LLVM=1 LLVM_IAS=1 ARCH=arm64 \
rk3588s-rock-5c.img -j8
关键产物:
| 文件 | 用途 |
|---|---|
kernel-5.10/arch/arm64/boot/Image |
包含内建 RKNPU 0.9.8 的 kernel |
kernel-5.10/vmlinux |
带符号内核,用于版本和符号检查 |
kernel-5.10/resource.img |
DTS/resource 产物 |
kernel-5.10/boot.img |
内核目标生成物,不一定是完整 Android boot |
检查源码和链接结果:
grep -E 'DRIVER_(DATE|MAJOR|MINOR|PATCHLEVEL)' \
kernel-5.10/drivers/rknpu/include/rknpu_drv.h
strings kernel-5.10/vmlinux | grep -F '0.9.8'
sha256sum kernel-5.10/arch/arm64/boot/Image
到这里完成的是“新内核编译”,还没有得到可以安全刷入真机的完整 boot 镜像。
串口日志已经显示:
Enter fastboot...OK
但 Windows 执行:
fastboot devices -l
没有任何输出。
U-Boot 中同时出现的:
ethernet address not set
No ethernet found
描述的是未使用的以太网启动路径,并不能证明 USB Fastboot 失败。应先检查
Windows 是否枚举了 USB gadget。
Get-PnpDevice -PresentOnly |
Where-Object { $_.InstanceId -match 'VID_18D1&PID_D00D' } |
Format-List Status,Class,FriendlyName,InstanceId,Problem
本次设备显示为:
FriendlyName: USB download gadget
Hardware ID: USB\VID_18D1&PID_D00D
Problem: CM_PROB_FAILED_INSTALL / code 28
这说明 U-Boot 已经通过 USB 把 gadget 暴露给 Windows,线材和 U-Boot USB
路径基本正常,但 Windows 没有绑定可供 Fastboot 使用的驱动。
常见 Rockchip USB 驱动主要匹配 VID_2207,而本次 U-Boot Fastboot gadget
使用 Google VID/PID:
18D1:D00D
Google USB Driver 的部分版本也没有直接列出 PID_D00D。不建议编辑签名
INF,或者为了添加一个硬件 ID 而关闭 Windows 驱动签名验证。
操作步骤:
USB download gadget;18D1:D00D;WinUSB;WinUSB,问题代码为 0。不要选择串口适配器、键盘、USB Hub 或存储设备,也不要将目标换成
libusbK 或 libusb-win32。
本次绑定 WinUSB 后,设备管理器已经显示正常,但 AOSP fastboot.exe 仍然
看不到设备。
原因是 Zadig 为 WinUSB 创建了随机 DeviceInterfaceGUIDs,而 AOSP Windows
Fastboot transport 通过固定 Android USB 接口 GUID 枚举设备:
{F72FE0D4-CBCB-407D-8814-9ED673D0DD6B}
下面先给出不依赖项目脚本的手动操作。所有 PowerShell 命令都必须在“以
管理员身份运行”的窗口中执行。
第一步,查找当前连接的 18D1:D00D 设备。正常情况下只能找到一个:
$devices = @(
Get-PnpDevice -PresentOnly |
Where-Object { $_.InstanceId -match 'VID_18D1&PID_D00D' }
)
$devices | Format-List Status,Class,FriendlyName,InstanceId,Problem
如果返回零个设备,应回到 USB 枚举、线材或 U-Boot Fastboot 状态继续排查;
如果返回多个设备,不要继续修改注册表,先断开无关设备。确认只有一个目标后:
$instanceId = $devices[0].InstanceId
第二步,确认 Zadig 已经为它绑定 WinUSB。返回值必须是 WinUSB:
$service = (
Get-PnpDeviceProperty -InstanceId $instanceId |
Where-Object KeyName -eq 'DEVPKEY_Device_Service'
).Data
$service
如果不是 WinUSB,先停止操作并回到上一节重新安装正确驱动。
第三步,定位设备参数注册表项,并查看已有 GUID:
$registrySubKey =
'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\' +
$instanceId + '\Device Parameters'
$registryPath = 'Registry::' + $registrySubKey
Get-ItemProperty -LiteralPath $registryPath |
Select-Object -ExpandProperty DeviceInterfaceGUIDs
第四步,在修改前导出注册表备份。这里使用当前用户的临时目录,不依赖工程
路径:
$backupDirectory = Join-Path $env:TEMP 'rk3588-fastboot-driver-backup'
New-Item -ItemType Directory -Force -Path $backupDirectory | Out-Null
$backupFile = Join-Path $backupDirectory `
'VID_18D1_PID_D00D-device-parameters-before-android-guid.reg'
reg.exe export $registrySubKey $backupFile /y
if ($LASTEXITCODE -ne 0) {
throw '注册表备份失败,停止修改。'
}
$backupFile
第五步,保留 Zadig 已创建的 GUID,并追加 AOSP Android USB GUID:
$androidInterfaceGuid = '{F72FE0D4-CBCB-407D-8814-9ED673D0DD6B}'
$currentGuids = @(
(Get-ItemProperty -LiteralPath $registryPath).DeviceInterfaceGUIDs
)
$updatedGuids = @(
$currentGuids + $androidInterfaceGuid | Sort-Object -Unique
)
New-ItemProperty -LiteralPath $registryPath `
-Name DeviceInterfaceGUIDs `
-PropertyType MultiString `
-Value $updatedGuids `
-Force | Out-Null
不要用新 GUID 覆盖原数组。DeviceInterfaceGUIDs 是多字符串值,正确操作是
保留原值后追加并去重。
第六步,只重启目标 PnP 设备,再验证 GUID 和 Fastboot:
pnputil.exe /restart-device $instanceId
Start-Sleep -Seconds 3
Get-ItemProperty -LiteralPath $registryPath |
Select-Object -ExpandProperty DeviceInterfaceGUIDs
fastboot devices -l
输出的 GUID 列表应包含 AOSP GUID,fastboot devices -l 应能列出目标设备。
如果希望以后重复使用同一套安全检查,本文附录还提供了完整 PowerShell 脚本,
它执行的就是以上步骤。
所有命令都显式指定设备,避免连接多台设备时操作错误目标:
fastboot devices -l
fastboot -s <DEVICE> getvar product
fastboot -s <DEVICE> getvar partition-size:boot
fastboot -s <DEVICE> getvar has-slot:boot
fastboot -s <DEVICE> getvar max-download-size
本次读取结果表明:
has-slot:boot 为 no;本次发现三个名称相似、来源却完全不同的文件:
| 文件 | 实际来源 | 实际大小 | 本次结论 |
|---|---|---|---|
kernel-5.10/boot.img |
内核目标生成物 | 小于完整产品镜像 | 缺少 Android 产品 ramdisk,不能直接刷 |
AOSP 产品 out/.../boot.img |
当前产品配置重新构建 | 82,679,808 字节 | 大于真机 boot 分区,且 ramdisk 不同 |
boot-rknpu-0.9.8-candidate.img |
真机 boot 为母版,只替换 kernel | 39,505,920 字节 | 离线校验和真机刷写均通过 |
真机 boot 分区只有 41,943,040 字节,即 40 MiB。因此前两个镜像都不能
直接用于当前设备。文件名同为 boot.img 并不表示内部结构或分区布局一致。
判断 boot 镜像能否使用,不能只看文件名或“编译成功”,必须比较:
在已授权的 userdebug 设备中:
adb -s <DEVICE> root
adb -s <DEVICE> wait-for-device
adb -s <DEVICE> shell \
"mkdir -p /data/local/tmp/rknpu-boot-backup"
adb -s <DEVICE> shell \
"blockdev --getsize64 /dev/block/by-name/boot"
adb -s <DEVICE> shell \
"dd if=/dev/block/by-name/boot \
of=/data/local/tmp/rknpu-boot-backup/boot-before-rknpu.img bs=4M"
adb -s <DEVICE> shell \
"sha256sum \
/data/local/tmp/rknpu-boot-backup/boot-before-rknpu.img"
adb -s <DEVICE> pull \
/data/local/tmp/rknpu-boot-backup/boot-before-rknpu.img \
<LOCAL_BACKUP_DIR>/boot-before-rknpu.img
PC 再计算一次 SHA-256,必须与设备一致。该文件是完整分区回滚备份,可能
包含设备特定信息,应保存在 Git 和无关服务器之外。
为复核本文步骤,升级完成后又对当前设备执行了一次相同的只读导出。公开记录
不保存设备序列号,命令通过 ADB 自动取得当前唯一在线设备:
$devices = @(
adb devices |
Select-String '\tdevice$' |
ForEach-Object { ($_ -split '\s+')[0] }
)
if ($devices.Count -ne 1) {
throw "预期一台在线 ADB 设备,实际为 $($devices.Count) 台。"
}
$device = $devices[0]
adb -s $device root
adb -s $device wait-for-device
adb -s $device shell getprop ro.product.device
adb -s $device shell getprop ro.build.version.release
adb -s $device shell readlink -f /dev/block/by-name/boot
adb -s $device shell blockdev --getsize64 /dev/block/by-name/boot
adb -s $device shell cat /sys/kernel/debug/rknpu/version
当前设备实际返回:
RadxaRock5C
12
/dev/block/mmcblk1p7
41943040
RKNPU driver: v0.9.8
本次复核导出的 40 MiB 当前 boot 镜像,设备端与 PC 端 SHA-256 均为:
9a0f4d909429ab8e480f3346bbb859e5efd0f6a6d89066d0c4c5fd6f9be2be1a
这个哈希对应升级后的完整 live boot 分区;回滚时仍应使用升级前保存的原始
0.8.8 完整备份,不能拿当前 0.9.8 镜像冒充回滚镜像。
使用当前 AOSP 源码树自带且版本配套的 unpack_bootimg.py 和
mkbootimg.py。它们通常位于:
<AOSP_ROOT>/system/tools/mkbootimg/unpack_bootimg.py
<AOSP_ROOT>/system/tools/mkbootimg/mkbootimg.py
不要从不明网站下载同名脚本,也不要跨 Android 大版本混用工具。先建立工作
目录并解包真机备份,同时保存工具输出:
mkdir -p <WORK_DIR>/original <WORK_DIR>/candidate-check
python <TOOLS_DIR>/unpack_bootimg.py \
--boot_img <LOCAL_BACKUP_DIR>/boot-before-rknpu.img \
--out <WORK_DIR>/original \
--format=mkbootimg | tee <WORK_DIR>/original-mkbootimg-args.txt
unpack_bootimg.py 的终端输出中会给出与当前镜像匹配的完整 mkbootimg
参数。先打开并保存它:
cat <WORK_DIR>/original-mkbootimg-args.txt
保留原镜像的:
手动复制工具输出的整条 mkbootimg 参数,把其中的 --kernel 改成新编译的:
kernel-5.10/arch/arm64/boot/Image
本次设备实际解包输出如下。路径已替换为公开占位符,其余数值均来自当前
真机,不是示例猜测值:
--header_version 2
--os_version 12.0.0
--os_patch_level 2022-07
--kernel <ORIGINAL_DIR>/kernel
--ramdisk <ORIGINAL_DIR>/ramdisk
--second <ORIGINAL_DIR>/second
--dtb <ORIGINAL_DIR>/dtb
--pagesize 0x00000800
--base 0x00000000
--kernel_offset 0x10008000
--ramdisk_offset 0x11000000
--second_offset 0x10f00000
--tags_offset 0x10000100
--dtb_offset 0x0000000011f00000
--board ''
--cmdline 'console=ttyFIQ0 firmware_class.path=/vendor/etc/firmware init=/init rootwait ro loop.max_part=7 androidboot.console=ttyFIQ0 androidboot.wificountrycode=CN androidboot.hardware=rk30board androidboot.boot_devices=fe2c0000.mmc,fe2e0000.mmc androidboot.selinux=permissive'
因此,这台 RK3588S2 / ROCK 5C 生成候选镜像时使用的完整命令如下。执行前
只需把前两行改成自己的源码目录和私有工作目录:
AOSP_ROOT="/path/to/android-source"
WORK_DIR="/path/to/private-rknpu-boot-work"
TOOLS_DIR="$AOSP_ROOT/system/tools/mkbootimg"
NEW_KERNEL_IMAGE="$AOSP_ROOT/kernel-5.10/arch/arm64/boot/Image"
python "$TOOLS_DIR/mkbootimg.py" \
--header_version 2 \
--os_version 12.0.0 \
--os_patch_level 2022-07 \
--kernel "$NEW_KERNEL_IMAGE" \
--ramdisk "$WORK_DIR/original/ramdisk" \
--second "$WORK_DIR/original/second" \
--dtb "$WORK_DIR/original/dtb" \
--pagesize 0x00000800 \
--base 0x00000000 \
--kernel_offset 0x10008000 \
--ramdisk_offset 0x11000000 \
--second_offset 0x10f00000 \
--tags_offset 0x10000100 \
--dtb_offset 0x0000000011f00000 \
--board '' \
--cmdline 'console=ttyFIQ0 firmware_class.path=/vendor/etc/firmware init=/init rootwait ro loop.max_part=7 androidboot.console=ttyFIQ0 androidboot.wificountrycode=CN androidboot.hardware=rk30board androidboot.boot_devices=fe2c0000.mmc,fe2e0000.mmc androidboot.selinux=permissive' \
--output "$WORK_DIR/boot-rknpu-0.9.8-candidate.img"
如果工具输出中没有 --second、--dtb 或某个 offset,就不要自行添加;如果
存在 --recovery_dtbo 等参数,则必须原样保留。原则是只改 --kernel 和
--output 两项,其余参数以及 ramdisk、second/resource、DTB 都沿用真机
备份。
本次实际组件记录:
| 组件 | 字节数 | SHA-256 |
|---|---|---|
新 kernel |
37,589,000 | bd6bf21edb6ab9f5af9fe31b2c1a8855e8ddf095af9953a66675041ea6d11df0 |
原 ramdisk |
1,351,166 | c3d95c0209d239c85b3f56eac7c24937d2e8414bea781341c66588abf7b6099d |
原 second |
324,096 | a8f92fd17658b112e21a3725c30730e56ef0ea304d8c3f16b5acb6d3dcd5bc7d |
原 dtb |
235,345 | 9dd391c1d8a10142f658ce70119b31fb6eb43b0d583240b6ac31ce7dde0d43b0 |
使用上述参数重新封装后得到:
文件:boot-rknpu-0.9.8-candidate.img
长度:39,505,920 字节
SHA-256:1a42fe060cf755bb306c620bc34f8c4826b642bedcffcbf5df8b476117dc8ff4
2026-08-24 再次从当前真机导出 boot、解包并按上述命令重新封装,得到的长度
和 SHA-256 与此前实际刷入的候选镜像完全一致,证明这组参数可以复现本次
候选镜像。
python <TOOLS_DIR>/unpack_bootimg.py \
--boot_img <WORK_DIR>/boot-rknpu-0.9.8-candidate.img \
--out <WORK_DIR>/candidate-check \
--format=mkbootimg
cmp <NEW_KERNEL_IMAGE> <WORK_DIR>/candidate-check/kernel
cmp <WORK_DIR>/original/ramdisk \
<WORK_DIR>/candidate-check/ramdisk
cmp <WORK_DIR>/original/second \
<WORK_DIR>/candidate-check/second
cmp <WORK_DIR>/original/dtb \
<WORK_DIR>/candidate-check/dtb
sha256sum <WORK_DIR>/boot-rknpu-0.9.8-candidate.img
如果原镜像包含 recovery_dtbo,也要进行相同比较。所有适用的 cmp 都应
成功,只有 kernel 可以发生变化。
本次容量结果:
真机 boot 分区:41,943,040 字节
候选 boot 镜像:39,505,920 字节
剩余空间: 2,437,120 字节
在已确认物理恢复方式的情况下,优先尝试:
fastboot -s <DEVICE> boot <CANDIDATE_BOOT_IMG>
本次主机返回:
Sending 'boot' OKAY
Booting OKAY
但设备最终仍运行旧 RKNPU 0.8.8。Pstore 表明 U-Boot 的 do_bootm() 返回
后复位,随后从旧 boot 分区启动。运行 kernel 大小也与候选不同。
因此 Fastboot OKAY 不能作为候选内核已经运行的证据。每次一次性启动后
必须在设备端核对:
adb -s <DEVICE> shell uname -a
adb -s <DEVICE> shell cat /sys/kernel/debug/rknpu/version
adb -s <DEVICE> shell "dmesg | grep -m1 'Initialized rknpu'"
正式烧录前重新读取整个 live boot 分区的 SHA-256,并与最初备份比较:
adb -s <DEVICE> root
adb -s <DEVICE> wait-for-device
adb -s <DEVICE> shell \
"sha256sum /dev/block/by-name/boot"
本次哈希完全一致,证明失败的一次性启动没有静默修改 boot 分区。
这是持久化且可能导致设备无法启动的操作。执行前必须确认:
下面是本次设备对应的完整 PowerShell 参考命令。公开文档不硬编码 Fastboot
序列号,而是要求当前只连接一台设备;执行前只需修改候选镜像路径:
$candidate = 'C:\path\to\boot-rknpu-0.9.8-candidate.img'
$expectedLength = 39505920
$expectedSha256 =
'1a42fe060cf755bb306c620bc34f8c4826b642bedcffcbf5df8b476117dc8ff4'
if (-not (Test-Path -LiteralPath $candidate)) {
throw "候选镜像不存在:$candidate"
}
$candidateFile = Get-Item -LiteralPath $candidate
$candidateHash = (
Get-FileHash -Algorithm SHA256 -LiteralPath $candidate
).Hash.ToLowerInvariant()
if ($candidateFile.Length -ne $expectedLength) {
throw "候选镜像长度不符:$($candidateFile.Length)"
}
if ($candidateHash -ne $expectedSha256) {
throw "候选镜像 SHA-256 不符:$candidateHash"
}
$fastbootDevices = @(
fastboot devices |
ForEach-Object { ($_ -split '\s+')[0] } |
Where-Object { $_ }
)
if ($fastbootDevices.Count -ne 1) {
throw "预期一台 Fastboot 设备,实际为 $($fastbootDevices.Count) 台。"
}
$fastbootDevice = $fastbootDevices[0]
fastboot -s $fastbootDevice getvar product
fastboot -s $fastbootDevice getvar has-slot:boot
fastboot -s $fastbootDevice getvar partition-size:boot
本次设备应返回非 A/B boot,即 has-slot:boot: no;boot 分区容量为
0x2800000,即 41,943,040 字节。确认设备身份和两项结果正确后,才执行真正
的写入命令:
fastboot -s $fastbootDevice flash boot $candidate
if ($LASTEXITCODE -ne 0) {
throw 'boot 分区写入失败,禁止继续执行自动重启。'
}
这条命令中的第一个 boot 是分区名,$candidate 是完整 Android boot
候选镜像。这里不能把 $candidate 改成裸 Image、kernel-5.10/boot.img
或超出分区容量的 out/.../boot.img。
本次 Fastboot 返回:
Sending 'boot' OKAY
Writing 'boot' OKAY
没有写入 vendor、system、recovery、vbmeta 或其他分区。
首次 fastboot reboot 因保留的 bootloader reason 又进入 Fastboot;
fastboot continue 后设备停在 U-Boot 提示符。
此时通过串口只读查看环境:
bootcmd=boot_android ${devtype} ${devnum};...
devtype=mmc
devnum=0
确认当前产品配置后执行:
boot_android mmc 0
该命令只启动已经写入 mmc 0 的 Android boot 分区,不会再次写入存储。
其他板卡的存储编号和 U-Boot 命令可能不同,不能直接照抄。
Android 启动后:
adb -s <DEVICE> wait-for-device
adb -s <DEVICE> shell getprop sys.boot_completed
adb -s <DEVICE> root
adb -s <DEVICE> wait-for-device
adb -s <DEVICE> shell uname -a
adb -s <DEVICE> shell cat /sys/kernel/debug/rknpu/version
adb -s <DEVICE> shell "dmesg | grep -m1 'Initialized rknpu'"
本次返回:
Linux localhost 5.10.160 #57 ... aarch64
RKNPU driver: v0.9.8
[drm] Initialized rknpu 0.9.8 20240828 ...
串口启动成功只证明这一次能够运行。还必须执行普通 Android 重启:
adb -s <DEVICE> reboot
adb -s <DEVICE> wait-for-device
adb -s <DEVICE> shell getprop sys.boot_completed
adb -s <DEVICE> shell cat /sys/kernel/debug/rknpu/version
本次设备无需 Fastboot 或串口干预,自动进入 Android,RKNPU 仍为 0.9.8。
至此才能确认 boot 分区更新持久有效。
如果新 boot 无法启动:
不要在设备身份、分区或备份完整性不明确时尝试回写。
检查设备驱动版本和 CONFIG
-> 备份原 drivers/rknpu
-> 解压官方 0.9.8 完整驱动
-> 应用 Linux 5.10 最小兼容补丁
-> 使用产品 config/DTS 编译
-> 从 vmlinux 和 Image 验证 0.9.8
串口确认 U-Boot Fastboot 已运行
-> Windows PnP 检查 18D1:D00D
-> Zadig 只为目标 gadget 绑定 WinUSB
-> 检查 DeviceInterfaceGUIDs
-> 备份注册表并追加 AOSP Android USB GUID
-> fastboot devices/getvar 只读验证
读取真实 boot 分区容量
-> 完整备份并双端校验哈希
-> 解包真机 boot
-> 只替换 kernel
-> 重新解包逐项比较
-> 校验候选容量和 Fastboot slot
-> 尝试一次性 boot 并从设备端判断
-> 再次确认 live boot 哈希未变
-> 获得授权后只 flash boot
-> 串口/Android 验证 RKNPU 0.9.8
-> 普通 reboot 验证持久性
如果不想逐条输入第三部分第 5 节的 PowerShell 命令,可将下面内容保存为
fix-windows-fastboot-guid.ps1,然后在管理员 PowerShell 中运行:
.\fix-windows-fastboot-guid.ps1
脚本默认自动寻找当前唯一的 18D1:D00D 设备。也可以显式指定设备管理器中
看到的 Instance ID:
.\fix-windows-fastboot-guid.ps1 -InstanceId '<INSTANCE_ID>'
完整源码如下:
[CmdletBinding()]
param(
[string]$InstanceId,
[string]$BackupDirectory = (
Join-Path $env:TEMP 'rk3588-fastboot-driver-backup'
)
)
$ErrorActionPreference = 'Stop'
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
$isAdmin = $principal.IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator
)
if (-not $isAdmin) {
throw '请在管理员 PowerShell 窗口中运行此脚本。'
}
if ([string]::IsNullOrWhiteSpace($InstanceId)) {
$matches = @(
Get-PnpDevice -PresentOnly |
Where-Object { $_.InstanceId -match 'VID_18D1&PID_D00D' }
)
if ($matches.Count -ne 1) {
throw "预期找到一个 18D1:D00D 设备,实际找到 $($matches.Count) 个。"
}
$InstanceId = $matches[0].InstanceId
}
$targetDevice = Get-PnpDevice `
-InstanceId $InstanceId `
-ErrorAction Stop
if ($targetDevice.InstanceId -notmatch 'VID_18D1&PID_D00D') {
throw "拒绝修改非目标 USB 设备:$($targetDevice.InstanceId)"
}
$deviceProperties = Get-PnpDeviceProperty -InstanceId $InstanceId
$service = (
$deviceProperties |
Where-Object KeyName -eq 'DEVPKEY_Device_Service'
).Data
if ($service -ne 'WinUSB') {
throw "预期设备服务为 WinUSB,实际为:$service"
}
$androidInterfaceGuid = '{F72FE0D4-CBCB-407D-8814-9ED673D0DD6B}'
$registrySubKey =
'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\' +
$InstanceId + '\Device Parameters'
$registryPath = 'Registry::' + $registrySubKey
if (-not (Test-Path -LiteralPath $registryPath)) {
throw "未找到目标注册表项:$registrySubKey"
}
New-Item `
-ItemType Directory `
-Force `
-Path $BackupDirectory | Out-Null
$backupFile = Join-Path `
-Path $BackupDirectory `
-ChildPath (
'VID_18D1_PID_D00D-' +
'device-parameters-before-android-guid.reg'
)
& reg.exe export $registrySubKey $backupFile /y
if ($LASTEXITCODE -ne 0) {
throw '注册表备份失败,未继续修改。'
}
$currentGuids = @(
(Get-ItemProperty -LiteralPath $registryPath).DeviceInterfaceGUIDs
)
$updatedGuids = @(
$currentGuids + $androidInterfaceGuid |
Sort-Object -Unique
)
New-ItemProperty `
-LiteralPath $registryPath `
-Name DeviceInterfaceGUIDs `
-PropertyType MultiString `
-Value $updatedGuids `
-Force | Out-Null
& pnputil.exe /restart-device $InstanceId
if ($LASTEXITCODE -ne 0) {
throw 'PnP 设备重启失败。'
}
Start-Sleep -Seconds 3
Write-Output 'Fastboot Android 接口 GUID 更新完成。'
Write-Output "注册表备份:$backupFile"
Get-ItemProperty -LiteralPath $registryPath |
Select-Object -ExpandProperty DeviceInterfaceGUIDs
if (Get-Command fastboot -ErrorAction SilentlyContinue) {
fastboot devices -l
}
脚本中的三项保护不要删除:限定 18D1:D00D、核对 WinUSB 服务、修改前
导出注册表。它们用于降低误修改其他 USB 设备的风险。
RK3588 RKNPU 驱动升级真正困难的地方,不是修改版本号,而是保证三个条件:
只要始终坚持“先只读验证、再生成候选、设备端证明、最后持久化写入”,就能
把一次高风险的内核升级拆解成可检查、可复现、可回滚的工程流程。
更完整的逐步操作和故障表可参考:
docs/04-rknpu-driver-compatibility.md;docs/05-local-llm-deployment-guide-zh.md。此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。