ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

UWE5621DS Linux驱动移植:SDIO中断与固件加载排坑指南

UWE5621DS Linux驱动移植:SDIO中断与固件加载排坑指南 最近在RK3568的板子上移植UWE5621DS这颗WiFi模组前前后后折腾了快一周。看着网上那些“几行配置就能跑通”的帖子再对比自己遇到的SDIO中断不触发、固件下载卡死、wlan0反复消失真有点怀疑人生。如果你也在搞这颗芯片尤其是从零开始移植Linux驱动我建议你把这篇看完——这里面的坑我基本都是实打实踩过来的能帮你省下好几个通宵。UWE5621DS是一颗很常见的低成本WiFi/BT Combo芯片SDIO接口挂WiFi、UART挂蓝牙国内不少平板、电视盒子、工控板都在用。驱动移植本身不算难难点集中在两块一是SDIO中断能不能正常触发二是固件能不能正确加载。这两个问题一旦出现系统日志不会直接告诉你“哪里写错了”只会扔出一堆超时、复位、下载失败的报错。所以这篇文章我不光给结论也把排查思路完整写出来希望你遇到类似现象时能按链路自己定位。1. 移植UWE5621DS之前先把这四件事搞清楚1.1 驱动源码、固件包和内核版本要对应UWE5621DS的驱动不是主线内核自带的驱动源码和固件一般由芯片原厂或开发板厂商提供常见目录是drivers/net/wireless/uwe5621/里面通常有unisocwifi、wcn、sdio、bt等子目录。这颗芯片的驱动对内核版本有一定要求一般建议4.19或5.10这类长期维护版本太老的内核可能缺mac80211相关的接口太新的内核又可能改了驱动框架导致编译报错。固件文件同样重要一般放在/lib/firmware/unisoc/目录下常见的名字有wcnmodem.bin、wcn.bin、nvram、boot32.bin等。不同SDK版本里固件命名有差异这很正常但你必须保证驱动源码和固件包来自同一套发布版本。我见过有人混用不同版本的固件和驱动现象是固件能下载完、wlan0也能看到但一连接AP就死机查了三天最后发现是固件与驱动的版本不匹配。1.2 硬件连接决定中断模式先对着原理图确认UWE5621DS的SDIO中断有两种工作模式一种是in-band中断复用SDIO协议的DAT[1]信号线靠host控制器在数据线上检测中断另一种是out-of-band中断OOB芯片会单独拉一根GPIO出来给host做中断脚。这两种模式在设备树上的配置完全不一样你第一步就要对着原理图确认模组到底把中断脚接到了哪里。很多移植出问题根源就在这里硬件上是OOB中断但设备树照着某个仓库的默认配置写的 in-band或者反过来。结果就是mmc1能识别到SDIO卡但通信过程各种超时。我的经验是先查原理图上WiFi芯片有没有一根独立的中断线连到SoC的GPIO如果有就是OOB模式如果没有大概率是in-band模式。这个判断要做在改设备树之前方向错了后面全是白忙。1.3 设备树SDIO节点不是“抄过来就能用”设备树里给SDIO控制器配节点很多人的做法是找一个相似平台的dts直接拷过来改一改compatible就把板子烧上了。这样做运气好能跑运气不好就是各种玄学报错。关键配置包括bus-width 4UWE5621DS用4线SDIO配成1线也能跑但性能差很多。cap-sdio-irq如果走in-band中断这个属性一般要加。non-removable贴片模组不会热插拔这个属性告诉内核不要做卡检测。keep-power-in-suspend休眠时保住SDIO供电否则醒过来要重新加载固件。mmc-pwrseq如果模组的电源和复位脚需要按顺序控制这里要挂一个电源序列。这些属性每一项背后都有具体含义不是可有可无的修饰。比如non-removable不配内核会周期性去扫描卡是否存在干扰正常通信严重时直接导致吞吐量抖动。1.4 供电和使能脚驱动跑不起来的第一嫌疑人WiFi模组的供电通常有两路一路是给SDIO IO供电的vmmc一路是给芯片核心供电的独立LDO。设备树里要确保这两路电压正确特别是IO域电压要和SoC的SDIO接口电压匹配常见的是1.8V或3.3V配错了SDIO通信会非常不稳定。UWE5621DS通常还有一个WIFI_EN/W_DISABLE使能脚由GPIO控制。这个脚在驱动加载前必须拉高芯片才能从关机状态醒来。如果WIFI_EN没拉高驱动加载时SDIO无法枚举到设备日志里直接显示卡不存在。这个使能脚可以放在板级初始化的GPIO控制里也可以放到mmc-pwrseq中管理。我建议用pwrseq方案它能保证时序是可控的比在驱动里随手gpio_set_value靠谱得多。2. SDIO中断问题从“mmc error -110”到稳定探测2.1 中断模式的判断in-band和OOB到底接的是哪种先解释一下为什么UWE5621DS对中断这么敏感。SDIO设备不像USB设备有独立的中断端点它要告诉host“我有事”要么在DAT[1]信号线上拉一个低电平in-band要么通过一根专用GPIO输出中断信号OOB。硬件上接了哪种驱动和内核就要用哪种方式去响应。如果是in-band模式你需要在设备树SDIO节点里加cap-sdio-irq属性让host控制器在DAT[1]上检测中断。如果是OOB模式则需要给代表WiFi模块的节点配置interrupt-parent和interrupts指向SoC的GPIO控制器并且指定正确的触发类型。UWE5621DS的OOB中断从我接触过的几款模组来看基本都是低电平触发IRQ_TYPE_LEVEL_LOW不是边沿触发。这一点非常关键后面我会讲为什么改成边沿触发会出大问题。2.2 设备树中断属性的正确配置OOB模式下设备树里大概是这样一段sdio1 { status okay; bus-width 4; cap-sdio-irq; keep-power-in-suspend; non-removable; #address-cells 1; #size-cells 0; wifi1 { compatible unisoc,uwe5621; reg 1; interrupt-parent gpio3; interrupts 5 IRQ_TYPE_LEVEL_LOW; reset-gpios gpio3 6 GPIO_ACTIVE_LOW; }; };这段里reg 1是SDIO功能号UWE5621DS一般挂在function 1上别写错。interrupts里的GPIO号和触发方式必须和原理图一致。如果你确认硬件是OOB但没加interrupt-parent和interrupts驱动收不到中断SDIO的cmd53数据操作就会一直等到超时。有一个细节要注意如果设备树里同时写了cap-sdio-irq又配了OOB中断的GPIO内核会优先尝试in-band模式导致你的GPIO中断一直不被使用。所以两种模式不要同时配二选一。2.3 我踩过的那次“中断触发方式”坑有一次我移植到一半wlan0能出来但一跑吞吐量测试就卡死dmesg刷屏mmc1: Timeout waiting for hardware interrupt mmc1: error -110 whilst sending SDIO command我最初怀疑是信号完整性把SDIO时钟从50MHz降到25MHz还是不行。后来用示波器抓中断脚发现正常情况下这个脚是个常态高电平、有事件时拉低的矩形波。而我的设备树里配的是IRQ_TYPE_EDGE_FALLING也就是下降沿触发正好只有第一次拉低能捕获到如果芯片在中断处理期间没有释放该引脚、或者host错过了边沿后续就再也触发不了。改成IRQ_TYPE_LEVEL_LOW之后问题立刻消失。因为电平触发模式下只要引脚处于低电平内核就会持续感知到中断请求不会因为错过一个边沿就永久失去响应。这是UWE5621DS移植里非常典型的一个坑强烈建议你直接确认硬件设计如果是低电平有效就老老实实用LEVEL_LOW。2.4 中断问题的排查链路如果你遇到了SDIO超时或中断不生效我建议按下面的顺序排查不要跳步确认硬件连接用万用表量中断脚在芯片工作时的电平看是不是常态高、事件低。确认中断有没有注册成功加载驱动后执行cat /proc/interrupts找到对应的GPIO中断号看触发次数是否为0。如果一直是0说明中断根本没有被触发。确认触发类型对照原理图检查设备树里interrupts的触发类型低电平有效就别写EDGE。确认有没有和其他外设抢GPIO有些SoC的GPIO默认被pinmux复用成了其他功能设备树里要显式把该引脚配置为GPIO输入模式。这一步漏了你连中断脚的电平都读不到。确认SDIO扫描是否成功dmesg | grep mmc里看有没有new SDIO card之类的日志如果没有说明问题在更前面的探测阶段。3. 固件加载从找不到固件到下载卡死3.1 固件目录、文件名和版本匹配UWE5621DS的固件加载和其他WiFi芯片不太一样它不只是加载一个fw.bin完事而是有一个完整的下载流程先通过SDIO给芯片发送命令、让芯片进入下载模式然后把主固件分段写入芯片内存最后启动固件、芯片主动上报版本信息。如果任何一个环节失败驱动都会报固件下载错误。常见的固件目录是/lib/firmware/unisoc/你可以用下面命令先确认文件是否完整ls -l /lib/firmware/unisoc/一般至少要有主固件和nvram配置。不同SDK里文件名可能不同我见过有wcnmodem.bin、有wcn.bin、也见过fw.bin。你不需要背文件名但一定要确认文件名与驱动源码里的宏定义一致。驱动里通常有个路径宏比如#define FIRMWARE_PATH /lib/firmware/unisoc/如果固件路径不对日志里会直接出现fail to get firmware、request_firmware failed之类的关键字。这种情况最好排查路径、文件名、文件是否真的打包进了rootfs。3.2 固件下载的日志怎么看固件下载阶段出现问题时dmesg往往会被刷屏你要抓住几个关键节点。下面是我总结的日志关键字和对应含义日志关键字含义优先排查方向request_firmware failed找不到固件文件路径、文件名、rootfs打包download firmware fail固件传输中途出错SDIO时钟、中断模式、电压firmware download timeout下载过程超时中断是否触发、CMD53是否异常chip version mismatch固件和芯片版本不匹配固件包选型load nvram failednvram配置加载失败nvram文件内容、路径看到download firmware fail这类日志时别一股脑去怀疑固件本身。大多数情况下固件包是没问题的真正的问题是数据通道不稳定。因为固件下载要走SDIO CMD53批量读如果中断响应不及时host会在传输中途超时。3.3 固件加载和SDIO中断的耦合问题这是很多人没意识到的坑固件加载失败根子却在中断配置上。我举一个真实的例子。有一块板子wlan0一直不出来dmesg里反复出现unisoc_wifi: download firmware fail unisoc_wifi: failed to load wifi firmware我一开始反复检查固件路径、文件权限、md5校验全都没问题。后来单独跑SDIO读写测试发现CMD53读操作经常超时。进一步排查发现就是因为OOB中断的GPIO设备树没配置host在传输过程中无法及时响应芯片的中断请求导致固件下载流程一直被中断超时打断。所以如果你的固件一直下载失败而且排除了路径、文件名、文件完整性问题之后请回头检查SDIO中断配置。这个耦合关系很多移植教程不会专门拿出来讲但它确实是最常见的“看起来是固件问题实际是中断问题”的场景。3.4 一个典型的cmd53超时排查实例有一次我调试cmd53超时日志是这样mmc1: error -110 whilst using SDIO CMD53排查链路如下降低SDIO频率把max-frequency从50MHz改到25MHz问题依旧排除纯信号速率问题。检查中断次数cat /proc/interrupts发现WiFi节点的中断号触发次数为0确认中断没通。检查原理图OOB中断接到了SoC的GPIO3_5但设备树里写成了GPIO3_7改回来后中断触发次数开始增长。固件下载成功中断正常后固件一次下载通过wlan0正常出现。这个例子说明排错时不能只看报错的信息cmd53报错时我们很容易认为是数据线问题实际却是中断系统根本没干活。越早去查中断触发次数越能少走弯路。4. 除了中断和固件这些细节决定你能跑多久4.1 时序复位、使能、探测的顺序不能乱UWE5621DS上电后需要先经过一段复位和稳定时间才能被SDIO控制器枚举到。如果你在驱动里一边拉高WIFI_EN一边马上扫描SDIO很可能会遇到“检测不到卡”的问题。正确的顺序是先给芯片供电再释放复位然后拉高使能脚等待几毫秒到几十毫秒最后再触发SDIO扫描。这个时序可以在设备树mmc-pwrseq里定义也可以在板级初始化代码里做。如果你发现芯片10次里有3次检测不到大概率是上电到扫描之间的延时不够。我习惯在pwrseq的post-power-on-delay-ms里配置一个保守的值比如100让芯片有足够的时间稳定。4.2 SDIO频率、电压和信号完整性SDIO频率不是一个“越大越好”的参数。UWE5621DS标称支持高速SDIO但在实际布线一般、模组飞线、或者使用杜邦线调试的情况下跑50MHz很容易出现偶发性的传输错误。我在调试阶段通常先用25MHz跑通全流程再尝试往上提。电压问题同样隐蔽。如果IO域电压不稳定最典型的现象是冷启动时WiFi正常跑一会儿就掉线dmesg里有cmd52或cmd53的写错误。这种问题在软件上看不到原因必须用示波器抓SDIO_CLK和DAT线看波形幅度和是否有毛刺。我建议在模组的电源引脚旁边加一个10uF的去耦电容效果立竿见影。4.3 WiFi和蓝牙共存的隐患UWE5621DS是WiFi/BT Combo芯片WiFi用SDIO蓝牙用UART但它们的射频前端共用一套天线。驱动里如果只处理WiFi固件而不加载蓝牙固件会出现一个很怪的问题WiFi扫描正常但连上AP之后吞吐量掉到几乎为零。原因是WiFi和蓝牙的共存机制需要双方固件都跑起来共同参与时分调度。只加载WiFi固件时芯片内部的共存逻辑没有完全初始化射频冲突时无法做出正确仲裁。所以即使你只在乎WiFi功能也建议把蓝牙固件一并放在固件目录里让Combo芯片整体跑起来。这个经验我第一次遇到时完全没往这方面想查了很久才确认是蓝牙固件缺失导致的。4.4 suspend/resume场景下会踩的坑如果你的产品需要支持休眠唤醒UWE5621DS还有一个经典问题休眠后wlan0接口还在但一执行 ping 或者扫描就卡死。多数情况下是因为休眠时SDIO供电被切断了唤醒后芯片处于未初始化状态而驱动的resume回调没有重新加载固件。解决方向有两个一个是在设备树SDIO节点里保留keep-power-in-suspend休眠时不要切断SDIO电源另一个是在驱动的resume流程中完整地重新做一遍固件加载和硬件初始化。前者省电较少但简单稳定后者省电更好但代码量不小具体看你产品的休眠功耗要求。我没有用非侵入式方案而是直接改驱动加了一个resume重加载逻辑实测下来更可靠。5. 验证与收尾怎么算真正移植成功了5.1 一个可复现的完整自测清单移植完成之后光看wlan0出现是不够的我建议按下面这套清单验收冷启动加载断电重启确认dmesg中SDIO枚举、固件下载、网络接口注册三个环节全部正常。扫描和连接用网络管理器或wpa_supplicant连接5GHz和2.4GHz AP确认扫描列表完整、连接不闪断。吞吐量双向测试使用iperf3分别测TCP上行、下行确认速率在合理范围且长时间跑不出现timeout。反复断连重连手动断开AP再重连20次观察是否有失败或需要重新加载驱动的情况。休眠唤醒测试执行多次echo mem /sys/power/state再唤醒确认WiFi接口功能正常。并发测试打开蓝牙扫描的同时跑WiFi吞吐量确认共存机制没破坏通信质量。每项测试我一般会跑一轮完整的才认为移植成功而不是看到wlan0存在就算完事。5.2 调试阶段的个人建议与扩展思路最后分享几个调试阶段很实用的手段。mmc-utils工具里有一个mmc命令可以在不加载WiFi驱动的情况下直接读写SDIO寄存器用来确认SDIO总线本身通不通非常方便。我自己习惯写一个小的SDIO读写测试模块先在干净的SDIO层做回环验证再往上跑WiFi驱动。这样把问题分层隔离很多疑难杂症能快速定位到是总线问题、中断问题还是固件问题。如果你是第一次移植UWE5621DS我建议你手里常备一个原始SDK的参考设备树不要只盯着某一块板子的配置。不同平台的设备树写法有差异但SDIO、中断、电源这三大块的逻辑是相通的。遇到问题先分层抽丝剥茧往往比反复试配置要高效得多。这颗芯片的整体架构放在那里中断通了、固件能加载、电源时序对了剩下的基本都是信号和适配问题并不会复杂到哪里去。
返回列表