3195 字
16 分钟
RK3528 板级调试记录

RK3528 网络与 WiFi 驱动修改迁移说明#

board 本文档整理本次 RK3528 板级调试中最终生效的修改,方便后续迁移到其它 SDK。

适用背景:

  • SoC:RK3528
  • 系统:Android 13 / Linux kernel 5.10
  • WiFi:AP6275S,SDIO 接口
  • 板载 GMAC PHY:RTL8211F,对应系统里的 eth1
  • PCIe 网卡:RTL8111F/RTL8168,对应系统里的 eth2

最终验证结果:

  • AP6275S WiFi 可正常工作,wlan0 可联网。
  • RTL8211F 已由 Realtek PHY 驱动识别,eth1 可拿 IP 并 ping 通网关。
  • RTL8111F/RTL8168 已由 r8168.ko 驱动绑定,eth2 可拿 IP 并 ping 通网关。
  • RTL8111F/RTL8168 RJ45 指示灯已点亮,生效 LED 配置值为 0x00ca

目前仍存在的问题:

  • OpenWRT SDK百兆网口握手满,仅10Mbps,怀疑delay没调好;
  • PCIE网卡跑不满千兆,约700Mbps;
  • SDIO网卡遇到两个无线设备UDP测速,负载过高,会直接搞炸SDIO链路和驱动

1. AP6275S WiFi 修改#

1.1 关闭 bcmdhd OOB 中断#

文件:

external/wifi_driver/bcmdhd/Makefile

修改:

-CONFIG_BCMDHD_OOB := y
+CONFIG_BCMDHD_OOB := n

原因:

  • 当前板级 host-wake/OOB 中断没有按原 SDK 默认方式使用。
  • 保留 OOB 时,bcmdhd 可能卡在 host-wake IRQ 相关初始化。
  • 关闭 OOB 后,WiFi 模块可正常加载和联网。

1.2 AP6275S DTS 板级项#

文件:

kernel-5.10/arch/arm64/boot/dts/rockchip/rk3528/rp-wifi-bt-vs2275s-rk3528.dtsi

当前可工作的关键点:

wireless_wlan: wireless-wlan {
compatible = "wlan-platdata";
rockchip,grf = <&grf>;
wifi_chip_type = "ap6275s";
status = "okay";
};

SDIO power sequence 当前使用:

sdio_pwrseq: sdio-pwrseq {
compatible = "mmc-pwrseq-simple";
pinctrl-names = "default";
pinctrl-0 = <&wifi_enable_h &clkm1_32k_out>;
post-power-on-delay-ms = <200>;
reset-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_LOW>;
};

SDIO 频率和模式当前做了保守处理:

&sdio0 {
max-frequency = <50000000>;
no-sd;
no-mmc;
supports-sdio;
cap-sd-highspeed;
keep-power-in-suspend;
non-removable;
mmc-pwrseq = <&sdio_pwrseq>;
/delete-property/ rockchip,use-v2-tuning;
/delete-property/ sd-uhs-sdr104;
status = "okay";
};

迁移注意:

  • reset-gpioswifi_enable_hclkm1_32k_out 必须按新板原理图确认。
  • 如果新板 host-wake IRQ 硬件连接可靠,可以重新评估 OOB;否则优先沿用 CONFIG_BCMDHD_OOB := n
  • max-frequency = <50000000> 是保守稳定值。新板信号质量确认后,可以再评估更高频率。

2. RTL8211F GMAC PHY 修改#

2.1 内建 Realtek PHY 驱动#

文件:

kernel-5.10/arch/arm64/configs/rockchip_defconfig

修改:

CONFIG_R8168=m
CONFIG_REALTEK_PHY=y

原因:

  • 未启用 CONFIG_REALTEK_PHY 时,RTL8211F 会按 Generic PHY 处理。
  • 启用后,系统可识别为 RTL8211F Gigabit Ethernet PHY。
  • 本次验证中,启用后 eth1 可正常千兆链路、获取 IPv4、ping 通网关。

迁移注意:

  • 这项影响内核镜像,需要重新编译并刷入 boot
  • 如果其它 SDK 使用模块化 PHY,也可以设为 m,但要保证模块被打包并在 GMAC probe 前可用。当前项目直接设为 y 更稳。

3. RTL8111F/RTL8168 PCIe 网卡修改#

3.1 确认 r8168 驱动配置#

文件:

kernel-5.10/arch/arm64/configs/rockchip_defconfig

需要保证:

CONFIG_R8168=m

当前 SDK 原本已有该配置,但模块没有被打进 vendor_dlkm,所以设备枚举后没有生成可用网口。

3.2 把 r8168.ko 打进 vendor_dlkm#

文件:

device/rockchip/rk3528/device.mk

修改:

BOARD_VENDOR_KERNEL_MODULES += \
device/rockchip/rk3528/rkvtunnel.ko \
kernel-5.10/drivers/net/ethernet/realtek/r8168/r8168.ko

原因:

  • CONFIG_R8168=m 只表示会编译模块,不代表模块会被放进镜像。
  • Android vendor kernel module 需要通过 BOARD_VENDOR_KERNEL_MODULES 等机制打包到 vendor_dlkm
  • 打包并刷入后,PCIe 设备 10ec:8168 可绑定到 r8168,系统生成 eth2

3.3 DTS 增加 PCIe 子节点和 LED 配置#

文件:

kernel-5.10/arch/arm64/boot/dts/rockchip/rk3528/rp-eth-pcie2gmac-rk3528.dtsi

当前可工作的 RTL8111F/RTL8168 子节点:

&pcie2x1 {
pinctrl-0 = <&custom_pcie_pins>;
reset-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>;
vpcie3v3-supply = <&vcc3v3_pcie20>;
status = "okay";
pcie@0,0 {
reg = <0x000000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
rtl8111h: pcie-eth@0,0 {
compatible = "pci10ec,8168";
reg = <0x000000 0 0 0 0>;
realtek,led-data = <0xca>;
};
};
};

当前可工作的 PCIe pinctrl:

&pinctrl {
pcie {
custom_pcie_pins: custom_pcie_pins {
rockchip,pins =
<4 RK_PC0 4 &pcfg_pull_none>,
<4 RK_PB5 4 &pcfg_pull_none>,
<4 RK_PC1 4 &pcfg_pull_none>;
};
};
};

说明:

  • compatible = "pci10ec,8168" 用来让内核给 PCIe 设备挂上 OF node。
  • realtek,led-data = <0xca> 是本板实测有效的 RJ45 LED 配置值。
  • 运行时读取 sysfs 会看到 ca000000,这是 device tree cell 的大端显示方式,对应值仍是 0x000000ca

迁移注意:

  • reset-gpiosCLKREQ#PERST#WAKE# pinctrl 必须按新板原理图确认。
  • 如果新 SDK PCIe 控制器节点名、bus 地址或 slot/function 不同,需要按实际枚举位置调整子节点。
  • 0x00ca 是本板 RTL8111F/RTL8168 指示灯实测有效值。其它磁性器件或 LED 接法不同,可能需要重新试 LED 值。

3.4 修改 r8168 驱动,消费 realtek,led-data#

文件:

kernel-5.10/drivers/net/ethernet/realtek/r8168/r8168_n.c

原厂 r8168 驱动只读取 CustomLED 寄存器,不会主动读取 DTS 里的 realtek,led-data。所以即使 DTS 写了 <0xca>,如果不改驱动,RJ45 灯仍可能不亮。

增加头文件:

#include <linux/of.h>

增加 helper:

static void
rtl8168_apply_dt_led_data(struct rtl8168_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
u32 led_data;
if (!pdev || !pdev->dev.of_node)
return;
if (of_property_read_u32(pdev->dev.of_node, "realtek,led-data", &led_data))
return;
tp->NicCustLedValue = (u16)led_data;
RTL_W16(tp, CustomLED, tp->NicCustLedValue);
dev_info(&pdev->dev, "apply realtek,led-data=0x%04x to CustomLED\n",
tp->NicCustLedValue);
}

rtl8168_init_software_variable() 中,读取默认 LED 后调用:

tp->NicCustLedValue = RTL_R16(tp, CustomLED);
rtl8168_apply_dt_led_data(tp);

rtl8168_init_one() 中,rtl8168_hw_reset(dev); 后再调用一次:

rtl8168_hw_init(dev);
rtl8168_hw_reset(dev);
rtl8168_apply_dt_led_data(tp);

为什么写两次:

  • 第一次保证驱动内部变量 NicCustLedValue 与 DTS 一致。
  • 第二次放在硬件 reset 后,避免 reset 把 CustomLED 恢复成芯片默认值。
  • 本次验证日志中能看到两次打印:
r8168 0000:01:00.0: apply realtek,led-data=0x00ca to CustomLED
r8168 0000:01:00.0: apply realtek,led-data=0x00ca to CustomLED

4. 编译步骤#

以下命令以 SDK 根目录 /home/elf/rk3528 为例。

4.1 修改 defconfig 或 DTS 后重编 boot#

涉及这些内容时需要重编并刷 boot

  • rockchip_defconfig
  • DTS / DTB
  • 内建驱动

命令:

Terminal window
cd /home/elf/rk3528
./build.sh -C -K -J4

生成的 boot 镜像位置按 SDK 输出为准,本次使用:

rockdev/Image-rk3528_box/boot.img

4.2 只改 r8168.ko 后重编模块#

如果只改了:

kernel-5.10/drivers/net/ethernet/realtek/r8168/r8168_n.c

可以只重编 r8168 模块:

Terminal window
cd /home/elf/rk3528/kernel-5.10
export PATH=/home/elf/rk3528/prebuilts/clang/host/linux-x86/clang-r450784d/bin:/home/elf/rk3528/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin:$PATH
make ARCH=arm64 LLVM=1 LLVM_IAS=1 CROSS_COMPILE=aarch64-linux-gnu- M=drivers/net/ethernet/realtek/r8168 -j4

然后重新打包 vendor_dlkm.img

Terminal window
cd /home/elf/rk3528
source build/envsetup.sh
lunch rk3528_box-userdebug
make vendor_dlkmimage -j4

输出位置:

out/target/product/rk3528_box/vendor_dlkm.img

5. 刷机步骤#

5.1 刷 boot#

Terminal window
adb reboot bootloader
fastboot flash boot boot.img
fastboot reboot

如果设备使用 A/B slot,需要按实际分区策略确认是否刷 boot_a / boot_b

5.2 刷 vendor_dlkm#

进入 userspace fastboot:

Terminal window
adb reboot fastboot
fastboot getvar is-userspace

确认输出:

is-userspace: yes

刷入:

Terminal window
fastboot flash vendor_dlkm vendor_dlkm.img
fastboot reboot

6. 验证命令#

6.1 AP6275S WiFi#

Terminal window
adb shell ip addr show wlan0
adb shell dmesg | grep -iE "bcmdhd|dhd|wlan"

预期:

  • wlan0 存在。
  • WiFi 固件加载成功。
  • 连接 AP 后可获取 IPv4。

6.2 RTL8211F eth1#

Terminal window
adb shell dmesg | grep -iE "RTL8211F|realtek|stmmac|eth1"
adb shell ip addr show eth1
adb shell ping -I eth1 -c 3 192.168.1.1

预期:

  • dmesg 中能看到 RTL8211F / Realtek PHY。
  • 插线后 eth1LOWER_UP
  • 可获取 IPv4 并 ping 通网关。

6.3 RTL8111F/RTL8168 eth2#

确认 PCIe 设备绑定到 r8168

Terminal window
adb shell readlink /sys/bus/pci/devices/0000:01:00.0/driver

预期:

../../../../../../bus/pci/drivers/r8168

确认 DTS LED 属性存在:

Terminal window
adb shell od -An -tx4 /sys/bus/pci/devices/0000:01:00.0/of_node/realtek,led-data

预期:

ca000000

确认驱动写入 LED 配置:

Terminal window
adb shell dmesg | grep -iE "realtek,led-data|r8168|eth2"
adb shell cat /proc/net/r8168/eth2/driver_var | grep NicCustLedValue

预期:

apply realtek,led-data=0x00ca to CustomLED
NicCustLedValue 0xca

确认链路和网络:

Terminal window
adb shell cat /sys/class/net/eth2/carrier
adb shell ip addr show eth2
adb shell ping -I eth2 -c 3 192.168.1.1

预期:

  • carrier1
  • eth2LOWER_UP
  • 获取 IPv4,本次实测为 192.168.1.226/24
  • ping 网关 3/3 成功,0% 丢包。
  • RJ45 物理灯点亮。

7. 本次关键实测结果#

RTL8111F/RTL8168 最终日志:

r8168 0000:01:00.0: apply realtek,led-data=0x00ca to CustomLED
r8168 0000:01:00.0: apply realtek,led-data=0x00ca to CustomLED
r8168: eth2: link up

driver_var

chipset_name RTL8168H/8111H
speed 1000
NicCustLedValue 0xca

网络:

eth2: 192.168.1.226/24
ping 192.168.1.1: 3 transmitted, 3 received, 0% packet loss

物理结果:

RTL8111F RJ45 指示灯已亮

8. 迁移到其它 SDK 时的检查顺序#

  1. 先确认 DTS 文件路径和实际被编译的 board dts。不要只改名字相似但未参与编译的 dts。
  2. WiFi 先确认 AP6275S 电源、reset GPIO、32K 时钟、SDIO 频率,再决定是否关闭 OOB。
  3. RTL8211F 先确认 CONFIG_REALTEK_PHY 已启用,再看 dmesg 是否仍是 Generic PHY
  4. RTL8111F/RTL8168 先确认 PCIe 枚举到 10ec:8168,再确认 r8168.ko 是否被打进 vendor_dlkm
  5. LED 不亮但网络正常时,优先检查 realtek,led-data 是否进入 OF node,以及 r8168 是否实际写了 CustomLED
  6. 如果新板 LED 接法不同,保留驱动读取 DTS 的机制,只替换 DTS 中的 realtek,led-data 数值重新刷测。

9. Android 跨板启动卡 U-Boot 的处理#

9.1 现象#

同一套 Android 镜像烧录到另一块 RK3528 板后,OpenWrt 可正常启动,但 Android 停在 U-Boot 命令行。

串口参数:

COM4, 115200

典型日志第一阶段:

boot mode: recovery (misc)
ANDROID: reboot reason: "recovery"
avb_slot_verify.c:774: ERROR: recovery: Error verifying vbmeta image: invalid vbmeta header
AVB verify failed
Android boot failed, error -1.

这说明 U-Boot 不是找不到 eMMC,也不是 DDR 初始化失败,而是 misc 分区里的 Android BCB 残留了 recovery 请求。

9.2 清除 misc 中的 recovery BCB#

本次实测在 misc 分区开头和 misc + 16KB 位置都能看到:

boot-recovery
recovery
--wipe_all

U-Boot 分区表中 misc 起始 LBA 为:

0x00008000

清除 misc 开头 0x40 个扇区即可同时覆盖 Android 10+ 的 0 偏移 BCB 和 Rockchip 老的 16KB 偏移 BCB:

mmc dev 0
mw.b 0x10000000 0 0x8000
mmc write 0x10000000 0x8000 0x40
mmc read 0x10000000 0x8000 0x40
md.b 0x10000000 0x100
reset

读回预期:

10000000: 00 00 00 00 00 00 00 00 ...

清除后,启动日志应从:

boot mode: recovery (misc)
RESC: 'recovery'

变成:

boot mode: None
RESC: 'boot'
ANDROID: reboot reason: "(none)"

9.3 清除 misc 后仍卡 AVB 的原因#

清掉 BCB 后,本次又遇到第二阶段失败:

Vboot=0, AVB images, AVB verify
lib/avb/libavb_user/avb_ops_user.c: trusty_read_rollback_index failed
avb_slot_verify.c:884: ERROR: vbmeta: Error getting rollback index for location.
AVB verify failed
Android boot failed, error -1.

同时 OP-TEE/RPMB 日志有:

tee_rpmb_verify_key_sync_counter: Verify key returning 0xffff000f
tee_rpmb_init: Verify key failed!
Make sure key here matches device key

本项目 Android 构建输出为开发状态:

BOARD_AVB_ENABLE=false

对应 vbmeta.img 信息:

Algorithm: NONE
Rollback Index: 0
Flags: 2

也就是说,开发版镜像本来不应因为 RPMB rollback index 阻塞启动。但当前 U-Boot 配置启用了 CONFIG_OPTEE_CLIENT=yread_rollback_index() 会去 OP-TEE/RPMB 读取回滚索引。换板后 RPMB key 不匹配,导致读取失败,最终让 AVB 校验失败。

9.4 U-Boot 修复补丁#

文件:

u-boot/lib/avb/libavb_user/avb_ops_user.c

read_rollback_index() 中增加:

static AvbIOResult read_rollback_index(AvbOps *ops,
size_t rollback_index_location,
uint64_t *out_rollback_index)
{
if (out_rollback_index) {
#ifndef CONFIG_ANDROID_AVB_ROLLBACK_INDEX
*out_rollback_index = 0;
return AVB_IO_RESULT_OK;
#endif
#ifdef CONFIG_OPTEE_CLIENT
...

原因:

  • 当前 u-boot/.configCONFIG_ANDROID_AVB_ROLLBACK_INDEX 未启用。
  • 开发版 BOARD_AVB_ENABLE=falsevbmeta.img 是 unsigned/debug 形态。
  • 在未启用 rollback index 保护时,直接返回 0 更符合开发版启动预期,也符合 avb_ops_user.h 中“read_rollback_index returns 0”的说明。
  • 这样不会改 Android 分区内容,只修改 U-Boot 的 AVB rollback index 读取策略。

迁移注意:

  • 这个补丁适合开发调试版 Android 镜像。
  • 如果量产启用了 AVB、安全启动、RPMB rollback index 管理,不要直接套用该绕过逻辑,应改为正确初始化 RPMB key 和 rollback index。

9.5 重编与刷入 U-Boot#

重编:

Terminal window
cd /home/elf/rk3528
./build.sh -U -J4

生成文件:

/home/elf/rk3528/rockdev/Image-rk3528_box/uboot.img

本次拉到 Windows 后的文件:

D:\LLLLZZZZZPPPPP\牛马派\3528\uboot.avb_rollback_skip.img

RKDevTool 烧录参数:

分区名:uboot
起始地址:0x00004000
字节偏移:0x00800000
大小:0x2000 扇区,也就是 4MB

只刷 uboot.img,不要刷 MiniLoaderAll.bin

9.6 本次验证结果#

刷入补丁后的 uboot.img 后,Android 可以继续启动,不再卡在 U-Boot 的:

trusty_read_rollback_index failed
AVB verify failed
Android boot failed, error -1

10. ./build.sh 完整镜像未带入驱动的处理#

10.1 现象#

单独刷入 boot.imgvendor_dlkm.img 后,AP6275S、RTL8211F、RTL8111F/RTL8168 都能正常工作;但重新执行:

Terminal window
cd /home/elf/rk3528
./build.sh

再烧录生成的完整 update.img 后,发现前面修改的以太网和 AP6275S 驱动没有出现在系统里。

10.2 根因#

当前 Android 13 工程启用了动态分区:

use_dynamic_partitions=true
build_super_partition=true
dynamic_partition_list= system system_dlkm system_ext vendor vendor_dlkm odm odm_dlkm product

vendor_dlkm 不是独立放进 update.img 的普通分区,而是被打包进 super.img 里的动态分区。

本次问题的关键点是:

  • 单独调试时刷 vendor_dlkm.img 可以生效。
  • 但完整镜像打包阶段使用的是 rockdev/Image-rk3528_box/super.img
  • 旧的 build.sh 在重新打包前没有强制重建新的 vendor_dlkm.imgsuper.img
  • mkimage.sh 只是把已有的 out/target/product/rk3528_box/super.img 复制到 rockdev/Image-rk3528_box/super.img,不会自动判断 vendor_dlkm 里的模块是否已经更新。

所以最终生成的 update.img 可能带着旧的 super.img,表现为完整烧录后看不到新驱动。

10.3 build.sh 需要补的动作#

建议在读取产品变量的位置增加:

Terminal window
PRODUCT_USE_DYNAMIC_PARTITIONS=`get_build_var PRODUCT_USE_DYNAMIC_PARTITIONS`

在 kernel 构建完成、外部 WiFi 驱动构建完成后,显式构建 RTL8168/r8168 模块:

Terminal window
if [ -d "$LOCAL_KERNEL_PATH/drivers/net/ethernet/realtek/r8168" ] &&
grep -q '^CONFIG_R8168=m' "$LOCAL_KERNEL_PATH/.config"; then
echo "Start build r8168 kernel module"
cd $LOCAL_KERNEL_PATH && make $ADDON_ARGS ARCH=$KERNEL_ARCH M=drivers/net/ethernet/realtek/r8168 -j$BUILD_JOBS && cd -
if [ $? -eq 0 ]; then
echo "Build r8168 kernel module ok!"
else
echo "Build r8168 kernel module failed!"
exit 1
fi
fi

在执行 mkimage.sh 之前,动态分区项目需要重建 vendor_dlkm.imgsuper.img

Terminal window
if [ "$PRODUCT_USE_DYNAMIC_PARTITIONS" = "true" ] ; then
echo "rebuild vendor_dlkm.img and super.img for dynamic partitions"
make vendor_dlkmimage -j$BUILD_JOBS
if [ $? -ne 0 ]; then
echo "Build vendor_dlkm image failed!"
exit 1
fi
make superimage-nodeps -j$BUILD_JOBS
if [ $? -ne 0 ]; then
echo "Build super image failed!"
exit 1
fi
fi

这样 ./build.sh 生成完整镜像时,会保证:

  • AP6275S 的 bcmdhd.ko 进入新的 vendor_dlkm.img
  • RTL8111F/RTL8168 的 r8168.ko 进入新的 vendor_dlkm.img
  • 新的 vendor_dlkm.img 被重新打进 super.img
  • 最终 update.img 使用的是新 super.img

10.4 本次验证结果#

重新执行:

Terminal window
cd /home/elf/rk3528
./build.sh -C -K -u -J4

构建日志中确认出现:

Start build exteranl wifi driver
Build exteranl wifi driver ok!
Start build r8168 kernel module
Build r8168 kernel module ok!
rebuild vendor_dlkm.img and super.img for dynamic partitions
Target vendor_dlkm fs image: out/target/product/rk3528_box/vendor_dlkm.img
Done writing image out/target/product/rk3528_box/super.img
Make update image ok!

本次生成的完整镜像为:

/home/elf/rk3528/rockdev/Image-rk3528_box/update-rp-rk3528-android13-lcd-20260726-153445.img

关键文件时间戳:

out/target/product/rk3528_box/vendor_dlkm.img 2026-07-26 15:31
out/target/product/rk3528_box/super.img 2026-07-26 15:33
rockdev/Image-rk3528_box/super.img 2026-07-26 15:33
rockdev/Image-rk3528_box/update-rp-rk3528-android13-lcd-20260726-153445.img 2026-07-26 15:34

已确认:

CONFIG_R8168=m
CONFIG_REALTEK_PHY=y
CONFIG_BCMDHD_OOB := n

resource.img 中能找到:

ap6275s-20260723-01
realtek,led-data

r8168.ko 中能找到 LED 补丁日志字符串:

apply realtek,led-data

super.img 解包查看动态分区元数据时,能看到:

Name: vendor_dlkm
Group: rockchip_dynamic_partitions
Attributes: readonly

10.5 迁移到其它 SDK 时的检查点#

  1. 先确认目标 SDK 是否启用动态分区。
  2. 如果 vendor_dlkmsuper.img 里,不能只重建 vendor_dlkm.img,还必须重建 super.img
  3. 如果完整包由 mkimage.sh 或厂商脚本生成,要确认它使用的是新 super.img,不是历史产物。
  4. CONFIG_R8168=m 只代表模块会编译,不代表一定会进入镜像;还需要检查 BOARD_VENDOR_KERNEL_MODULES
  5. AP6275S 的 bcmdhd.ko、RTL8111F/RTL8168 的 r8168.ko 都应在 vendor_dlkm/lib/modules/ 下确认。
  6. RTL8211F 的 CONFIG_REALTEK_PHY=y 属于 boot/kernel 侧修改,烧完整包时也要确认 boot.img 是最新生成的。
RK3528 板级调试记录
https://creeper666.top/posts/3528-board-dev/
作者
Creeper666
发布于
2026-07-25
许可协议
CC BY-NC-SA 4.0