RK3588平台aic8800 WiFi调试全记录:从SDIO识别到吞吐量优化
BSP调试系列写到第6篇这次记录的是RK3588平台上的aic8800 WiFi调试。起因不算复杂项目上的旧WiFi模块突然缺货供应商推荐换aic8800SDIO接口内核SDK里也有配套驱动看起来是个“改改设备树、编一下内核”的活。我当时也和同事说快则一天慢则两天结果实际调下来前前后后花了一个多星期。这篇文章不重复那些网上随便能搜到的“移植教程”重点记录容易踩、而且不太容易搜到解决方案的细节包括SDIO识别、驱动选型、固件路径、射频校准、吞吐量上限和休眠唤醒希望给正在RK3588或类似平台上碰这颗芯片的人提个醒。不管你是刚接触BSP的新人还是已经调过几颗WiFi芯片的老手这篇文章应该都有点参考价值。新人可以把它当成一条完整的排错路径来读知道遇到问题该按什么顺序去看老手可以直接跳到第2节和第4节那两块是我这次消耗时间最多的部分。1. 项目背景与硬件环境为什么这颗芯片值得单独开一篇1.1 换芯的真实原因和选型约束先说项目背景。我手上的方案是一块RK3588核心板加底板的组合系统跑Linux产品形态是边缘计算网关。原先设计用的WiFi芯片供货出问题采购那边给的压力很大要求尽快找一个可以替代的方案。供应商推荐了aic8800理由很简单SDIO接口硬件改动最小软件上也有配套的Linux驱动同时它是WiFi 6芯片支持2.4G/5G双频理论速率比原来的方案高不少。于是“换芯”这个任务就到了BSP手上。这里有个事情必须先说清楚换WiFi芯片不是换一个设备树节点那么简单。SDIO接口虽然通用但每一颗芯片的上电时序、复位逻辑、固件加载方式、驱动对内核版本的要求都不一样。RK3588的SDK通常自带几款WiFi芯片的驱动但aic8800不一定在默认列表里。所以换芯的实际工作量包括确认硬件连接、补设备树、编译驱动、放固件、跑射频校准、最后把吞吐量和稳定性都测到位。任何一步出问题都会表现为“WiFi起不来”或者“能连上但网速很怪”。1.2 硬件连接方式与调试基线板子上aic8800通过SDIO连接RK3588走的是SDIO 3.0接口4-bit模式。除了SDIO_CLK、SDIO_CMD、SDIO_D0-D3还要注意WiFi芯片的reset引脚和power引脚。我这边调试时主板上的reset信号由一颗GPIO控制power则由板级供电电路直接给电。如果你拿到的是模组而不是芯片模组通常自带电源管理只需要关注reset和SDIO信号即可。调试基线信息如下SoCRK3588WiFi芯片aic8800SDIO系统LinuxSDK自带内核版本为6.1文件系统Buildroot构建rootfs可写USB网卡不作为参考所有测试都走SDIO WiFi因为板子的串口和adb都能用我建议调试时全程盯着两个东西串口串口里的内核日志以及dmesg | grep -E aic|mmc|wlan的输出。WiFi驱动不像GPU或NPU它的状态好坏有大量线索藏在mmc子系统和cfg80211的日志里只看应用层是远远不够的。2. SDIO识别第一关设备树配置与上电时序2.1 设备树节点几个最容易写错的字段RK3588的SDIO控制器在设备树里通常挂在sdhci上不同SDK节点名字可能有差异有的叫sdmmc有的叫sdhci0我这边用的是sdhci。aic8800的设备树节点和常见SDIO WiFi模组类似核心部分如下sdhci { status okay; max-frequency 50000000; bus-width 4; non-removable; broken-cd; cap-sdio-irq; keep-power-in-suspend; mmc-pwrseq wifi_pwrseq; vmmc-supply vcc3v3_sd; vqmmc-supply vcc1v8_sd; }; / { wifi_pwrseq: wifi-pwrseq { compatible mmc-pwrseq-simple; reset-gpios gpio3 RK_PB4 GPIO_ACTIVE_LOW; post-power-on-delay-ms 10; power-off-delay-us 100; }; };这里有几个字段不是随便写的。non-removable告诉mmc子系统这是一颗贴死的WiFi芯片不是可插拔的SD卡broken-cd禁用了卡检测引脚因为SDIO WiFi通常不接CD引脚如果不写这个字段内核会一直等待卡插入事件导致设备永远识别不到。这两个字段漏掉任何一个表现在外的现象都特别像“硬件没焊好”实际上是设备树没写好。cap-sdio-irq允许SDIO设备使用带内中断aic8800的驱动会依赖这个能力丢了的话驱动加载可能正常但后续收包会伴随大量中断轮询吞吐量直接受损。keep-power-in-suspend则告诉mmc子系统在系统休眠时不要切断WiFi电源这个字段和后面休眠唤醒的稳定性直接相关。2.2 上电时序那7毫秒的坑设备树写完编译烧录开机我满以为dmesg会直接看到类似new SDIO card的日志。结果等了半天内核日志里只有一行mmc1: error -110 whilst initialising SDIO card-110是超时。SDIO枚举卡的时候芯片没有在预期时间内回应。第一反应查硬件拿示波器看CLK、CMD、D0-D3波形信号本身是有的电平也正常。后来怀疑是上电时序问题。翻aic8800驱动包的文档里面明确写了reset信号拉高后需要等待至少10ms再发起SDIO访问。我设备树里post-power-on-delay-ms写的是10理论上刚好在临界值但实际板子电源纹波偏大10ms不够。把延时改成30之后第一次识别仍然不稳定大概三次开机有一次会失败。最终是把控制方式从mmc-pwrseq-simple改成在驱动里做reset驱动probe时先拉低reset延时20ms再拉高再延时50ms。这之后识别成功率才算稳定。我的建议是如果你也遇到error -110别急着怀疑硬件虚焊先拉长上电时序到30ms以上用排除法把软件因素干掉。2.3 识别成功的标志设备树和时序都调正常后dmesg里出现的日志应该是这样的mmc1: new high speed SDIO card at address 0001同时会出现wlan相关的设备注册信息。这时你可以检查一下/sys/bus/sdio/devices/下面有没有新设备目录如果驱动已经绑定通常能看到类似wlan0的网络接口。到这一步SDIO的第一关才算过。如果你能看到new high speed SDIO card但没有生成wlan0说明SDIO识别没问题问题在驱动编译和加载环节。3. 驱动编译选型fdrv、std、usb这些坑3.1 先搞清楚驱动包的目录结构aic8800的驱动源码在SDK里一般以aic8800_fdrv、aic8800_bsp这样的目录出现。我拿到的是完整驱动包里面有aic8800_fdrv和aic8800_std两种模式。名字上看fdrv是FullMAC驱动std是SoftMAC驱动。FullMAC和SoftMAC的区别简单说就是FullMAC驱动把大部分WiFi协议栈的事情放在固件和驱动内部处理上层只需要通过cfg80211接口控制它实现简单稳定性比较好SoftMAC则依赖内核的mac80211子系统灵活性高但调起来要多留意内核协议栈的配合。aic8800在RK3588这种Linux平台上直接用fdrv就对了。std模式一般给需要深度定制MAC层行为的场景用普通产品用不上。另一个目录aic8800_bsp是芯片的板级支持包包含一些底层工具和补丁我在实际编译时没有直接把它编进内核它更多是配合烧录、校准和调试用的。3.2 Kconfig里的选择项和依赖进入驱动目录后先看Kconfig把内核配置打开。不同SDK版本里配置项名称会变我在实际编译时看到的是这样几个关键项CONFIG_AIC8800_SDIOy CONFIG_AIC8800_FDRVy # CONFIG_AIC8800_STD is not setCONFIG_AIC8800_SDIO是SDIO总线接口支持如果你的板子用USB接口就选对应的USB选项。CONFIG_AIC8800_FDRV是FullMAC模式开关这个必须选。另外驱动依赖CONFIG_CFG80211内核里要确保已经打开否则编译的时候会报一堆未定义符号。有没有注意到这里我没有开802.11ax相关的配置其实驱动默认会通过固件能力自动协商不需要在内核Kconfig里单独指定真正的HE/WiFi6能力看的是固件版本和AP端是否支持。第一次弄的时候我还专门去找“Enable 802.11ax”的选项找了半天没找到后来实际连WiFi 6路由时速率跑到了1200Mbps才明白驱动不需要额外开关。3.3 编译加载后怎么确认驱动工作正常驱动编译成模块放到/lib/modules/对应目录modprobe aic8800_fdrv加载。正常加载后dmesg应该能看到类似这样的输出aic8800: sdio wifi init start aic8800: sdio wifi init success wlan0: created如果卡在某一步没往下走多半是固件没加载或固件路径不对这个在下一节详细说。这里补充一个我踩过的小坑RK3588 SDK里同一颗芯片可能被默认编成了STD模式和FDRV模式冲突。两个都编成y会导致加载时函数符号冲突modprobe直接报错。务必确认内核里只保留一种模式。驱动注册成功只是第一步真正让WiFi工作起来固件和射频参数才是大头。4. 固件加载失败的排查链路看着像权限问题实际是路径问题4.1 固件放哪里三类路径都要试aic8800的固件不是编进内核的而是以文件形式放在文件系统里驱动通过request_firmware()去读。固件文件的后缀一般是bin但具体文件名和路径因驱动版本而异。拿到驱动包后在fw目录里能找到类似aic8800_sdio_fw.bin、aic8800_sdio_fw_bsp.bin之类的文件。我第一次加载驱动时dmesg直接显示aic8800: request_firmware failed, ret -2-2就是文件不存在。因为驱动代码里写死的路径可能有好几个候选比如/lib/firmware/aic8800//vendor/firmware/aic8800//etc/firmware/aic8800/我一开始把固件放到了/lib/firmware/aic8800/结果还是报-2。查驱动源码才发现它优先去/vendor/firmware/aic8800/找找不到才去/lib/firmware。而Buildroot的文件系统默认不创建/vendor目录。所以排查这类问题不要看路径“顺不顺眼”直接打开驱动源码搜索request_firmware看里面拼接的路径前缀是什么。这一步是纯经验问题不同版本差别很大。4.2 固件拷贝之后必须检查文件大小另一个坑是固件文件名的长度和文件大小可能会影响加载结果。固件文件拷过去后第一件事是md5sum对比确认和驱动包里的一致不要用U盘从Windows复制到Linux后发生文件截断。我曾经遇到一次现象固件不报-2了但驱动卡在“download fw”阶段日志停在某个CRC校验的地方。查了半天发现是文件系统分区剩余空间不足固件实际写入失败但cp没有报错。所以拷完固件顺手df -h看一眼磁盘剩余空间是个好习惯。4.3 固件版本和驱动代码的匹配问题固件和驱动版本要配套这个原则很多人不重视。我手上这个SDK里驱动包带了多个固件目录不同版本对应不同的配置文件。比如支持WiFi 6完整功能的固件和支持基础802.11ac的固件大小可能差不少。如果驱动代码要求的是新版固件接口而你放了旧版固件加载时不会直接报错但后面连上AP后会频繁断线、吞吐量上不去、加密认证失败。判断固件和驱动是否匹配的最简单方法是去驱动包的README或release_note里找固件版本号再把固件文件里字符串拉出来看。也可以用strings命令查看固件开头附近的版本标记。如果版本对不上宁可多花时间重新整理固件目录也不要带着错配版本继续调。5. 射频校准、MAC地址和信道管制默认参数能用但不敢用5.1 为什么吞吐量在5G频段只有一半先查校准驱动加载完、固件也正常之后wlan0出现了wpa_supplicant也能连上AP。但我一测速率就发现问题5G频段连接速率只有433Mbps而且实际TCP吞吐量跑不到200Mbps。本来WiFi 6在80MHz频宽下、2路空间流理论速率应该到1200Mbps。怀疑是天线或者SDIO瓶颈但先查射频参数才是最稳妥的。aic8800这类芯片出厂时不一定预先烧录校准参数。没有校准数据时驱动会加载一套默认的射频参数能工作但发射功率、频偏、接收灵敏度都不是最优状态。表现在现象上就是连接速率上不去、距离一远就掉线、TX/RX吞吐量明显偏低。如果要查芯片里有没有有效校准数据可以用驱动调试工具或原厂提供的测试命令通常能读到类似“calibration data valid/invalid”的状态。我这边的板子第一次查就是invalid说明芯片出厂时没有做过校准。5.2 走一遍校准流程并保存nvram校准流程本身需要原厂工具具体命令不同版本不一样我不在这里贴具体命令但大致流程是这样把芯片置于测试模式连接频谱仪或直接用传导测试环境跑发射功率校准、接收灵敏度校准、频偏校准最后生成一组校准参数。校准完的参数要么烧进芯片的efuse/hidden flash区要么以nvram文件的形式放到文件系统里由驱动加载。我这边的情况是使用原厂调试工具完成校准后生成nvram文件放到指定目录驱动起来时会自动读取并报告“calibration data OK”。之后再测同样一台路由器5G频段连接速率从433Mbps升到1200Mbps实际TCP吞吐量也从不到200Mbps升到了接近800Mbps。所以如果你拿到一块新的aic8800模块丢到板子上只要能连但速率不达标第一件事不是调整设备树时钟而是查校准数据。5.3 MAC地址掉电就变它本来就没烧录MAC地址的问题和校准数据类似。很多WiFi模块出厂时会有一个全球唯一的MAC地址烧在芯片内部。但aic8800这颗芯片如果出厂前没烧MAC驱动就会在每次启动时根据某个随机数生成一个地址。现象就是每次重启ifconfig wlan0看到的MAC地址都不一样。如果产品需要固定MAC做MAC白名单或设备管理这个必须处理。处理方法有两种一是产品量产时用原厂工具把MAC地址烧进芯片二是在系统启动脚本里从其他存储位置读出预设MAC再用ip link set dev wlan0 address XX:XX:XX:XX:XX:XX来覆盖。这里还有一个小坑Linux上wpa_supplicant默认可能会使用随机MAC地址隐私MAC所以调试时看到的MAC和外包装标签上不一样不代表芯片有问题。等系统起来后手动改一次MAC是最快的确认方式。5.4 信道和地区码不是所有信道都能用aic8800默认的地区码不一定是中国区。如果固件里的默认region是US它会支持14信道、5G频段的部分信道是DFS信道或跟我们这边监管要求不一致。WiFi能正常工作不表示信道合规。系统正式出货前一定要确认2.4G频段只使用1-13信道不包括14信道5G频段的可用信道要按当地监管要求配置确保驱动没有把DFS信道当成普通信道无脑使用用iw reg get可以查看当前region用iw reg set CN可以临时把地区码切到中国区。不过更可靠的做法是在系统启动早期、驱动启动之前通过配置文件把region设好避免运行期间突然切换导致已连接设备断线。6. 吞吐量实测与优化连接速率好看实测才是真理6.1 从iperf3的角度看WiFi性能瓶颈WiFi调试到“能连上AP”之后还不能算完。我习惯用iperf3做TCP和UDP双向吞吐量测试用ping做延迟测试连续跑10分钟以上看波动。做iperf3测试时有几个细节很容易被忽略。第一虽然iperf3默认是单向测试但WiFi的TDMA调度会让双向并发吞吐量远低于单向第二TCP单线程在大带宽下可能被CPU瓶颈卡住不能一上来就抱怨固件不行。我这边测试时的经验是先在PC端开iperf3 -s嵌入式设备跑iperf3 -c PC的IP -t 60记录TX方向再反过来PC跑iperf3 -c 设备IP -t 60记录RX方向。两个方向都要测。如果设备CPU较弱在设备端跑服务器模式、PC跑客户端更能反映实际WiFi链路能力。但不同的接口方向消耗的CPU资源不一样最好两个方向都用两种跑法各测一轮选取最平衡的数据。6.2 5G连接速率正常但TCP吞吐量偏低我遇到过一种很迷惑的情况5G连接速率显示1200Mbps但TCP吞吐量无论怎么测都只有300Mbps左右。一开始怀疑是SDIO总线瓶颈。但SDIO 4bit 50MHz的理论带宽是200Mbps级别实际有效吞吐大概在100-150Mbps如果只能跑300Mbps反而说明SDIO不是瓶颈不对这里要理清楚WiFi 5G 80MHz下的物理层速率1200Mbps是链路层速率TCP吞吐本来就要打对折再打对折但打到300Mbps也还是偏低了。后来定位到问题出在板级设计WiFi芯片的SDIO数据线走线过长、过孔太多导致SDIO总线实际工作频率不稳驱动自动降频到了25MHz。25MHz的SDIO 4bit总线有效吞吐上限大约就是300Mbps正好和现象吻合。把设备树里max-frequency明确设为50000000同时把SDIO走线的等长和参考平面处理好后吞吐量才真正回到800Mbps以上。这里提醒一下max-frequency是上限不是实际工作频率mmc子系统会根据环境和芯片能力自适应。如果你在设备树里配了100MHz但硬件不达标系统可能自己降到25MHz。排查时直接读/sys/kernel/debug/mmc1/ios看到的实际时钟频率比猜靠谱得多。6.3 RX方向掉速天线和路径衰减的排查测试中还发现RX方向设备接收方向比TX方向吞吐量低很多同样一台PCTX能到800MbpsRX只有400Mbps。这个问题排查起来比较繁琐。先排除协议层干扰确认路由器没有开启节能模式和节流再用不同的AP交叉测试。但最终定位到天线匹配上WiFi天线离底板的电源模块太近电源噪声耦合到了天线路径上导致RX灵敏度下降。把天线从电源模块旁边移开几厘米RX吞吐量明显回升。如果你也遇到类似现象我建议按这个顺序排查AP信道是否拥挤、附近有没有强干扰源、天线位置和方向、天线馈线的接地处理最后再怀疑芯片本身。WiFi芯片的RX性能其实很难通过驱动参数改善大部分“RX差”都是天线或电磁环境问题。7. 稳定性专项挂起、休眠唤醒和固件崩溃恢复7.1 长时间压力测试ping包不能停吞吐量达标了稳定性测试也不能省。WiFi驱动的稳定性问题往往不是开机能发现问题而是长时间运行或从休眠唤醒后才暴露。我这边稳定性测试分三层第一层是连续12小时双向iperf3吞吐量压测第二层是ping测试从开机开始一直跑每丢一个包记录一次第三层是频繁休眠唤醒循环。第一层和第二层一起跑高负载和低负载场景都覆盖。实测中遇到过一个比较隐蔽的问题长时间压测到5小时左右wlan0突然消失dmesg里出现wlan0: TX timeout。这种看上去像驱动崩溃但根因其实是SDIO总线长时间高负载下发生了一次错误跟着设备掉线重枚举。7.2 休眠唤醒后WiFi失效的处理休眠唤醒是最容易踩坑的场景没有之一。RK3588支持Suspend to RAM系统休眠时WiFi如果彻底断电唤醒后SDIO设备重新枚举驱动状态可能丢失。我在设备树里加了keep-power-in-suspend确保系统休眠时WiFi供电不断。但仅仅这样还不够唤醒后WiFi还是连不上AP。排查后发现是WiFi芯片的reset GPIO在唤醒时被系统拉低又拉高但SDIO控制器还保留着休眠前的旧状态导致重新枚举时序错乱。解决方式是在驱动或板级休眠回调里确保唤醒后先重新初始化mmc控制器再让WiFi芯片复位顺序不能反。如果你是在Android系统上做类似调试还要注意WiFi框架层有自己的一套休眠管理BSP层面驱动的状态机必须和框架层保持一致。最直接的验证方法是执行echo mem /sys/power/state手动休眠再按任意键唤醒立刻观察dmesg和wlan0状态。这个测试至少要连续循环50次我这边跑到第40次左右暴露了偶发唤醒失败的问题。7.3 固件崩溃后的恢复机制aic8800的固件在极端情况下也可能崩表现为WiFi接口还在但扫描不到任何APdmesg也不一定有明显报错。这种情况下最简单的办法是卸载驱动再重新加载。但产品化之后不能靠人手动去rmmod/modprobe。建议在BSP层面加一个WiFi状态监控脚本或内核看门狗机制周期性检测wlan0是否存在、能否正常扫描到AP、有没有持续丢包一旦判断异常自动触发驱动重载或重启WiFi子系统。这个机制不需要太复杂但要保证监控进程本身不会因为WiFi异常而一起挂掉最好由独立的系统服务来跑。8. 调试工具和最后的经验总结这次调试过程里用的工具整理一下dmesg排查SDIO识别、驱动加载、固件加载的第一入口ifconfig/ip确认wlan0状态和MAC地址iw查看连接速率、信道、region信息iperf3吞吐量测试必须双向都跑/sys/kernel/debug/mmc1/ios查看SDIO总线实际时钟频率mmc-utils直接操作SDIO设备寄存器排查识别问题很有用串口ping脚本长时间稳定性测试工具不在多关键是每个工具要用对时机。SDIO识别阶段重点看dmesg和/sys/kernel/debug/mmc1/固件加载阶段重点看dmesg里的request_firmware结果射频和速率阶段重点用iw和iperf3休眠唤醒阶段重点看唤醒时序和驱动状态。最后整理几条最有价值的经验给后来者第一aic8800这颗芯片在SDIO接口下绝大多数识别问题不是芯片坏了而是设备树字段不完整或上电时序不够长。先拉长时序、补上broken-cd和non-removable能省下大量无意义的硬件检查时间。第二固件加载失败时不要盲目改权限或反复拷贝固件。先看驱动源码里的固件路径再确认文件系统空间最后确认固件和驱动版本配套。路径问题占七成版本问题占两成权限问题其实很少见。第三校准数据是WiFi性能的地基。没有校准数据的芯片能连上AP但吞吐量和灵敏度都处于“能用但很难看”的状态。做板子定型前第一件事就是确认校准数据有烧录、有备份、有量产流程。第四SDIO WiFi的性能上限不只由芯片决定还由PCB走线、天线位置、电源噪声共同决定。设备树配的max-frequency只是一个声明真正的瓶颈要去看实际跑出来的ios信息。BSP调试试错的过程大部分时间是枯燥的但每解决一个问题对这颗芯片、这套平台的理解就深入一层。这一篇写下来也算给自己留个备忘录。下一次再碰同类WiFi芯片至少知道先看哪几个点。希望这些记录对你也有帮助。