资讯动态

MTK Android 8.1 SD卡驱动能力修改:从20MB/s到满速的dts与caps调优实战

发布时间:2026/10/14 17:23:35 来源:尧图企业网站定制
前阵子处理一个基于MTK平台的Android 8.1定制系统项目客户反馈SD卡插上后能识别可实际读写速度只有20MB/s上下而同一张卡换到另一台设备上能跑出60MB/s。同平台基线工程用的是同一套BSP为什么表现差这么多查到最后根本不是卡的问题而是驱动侧对SD卡能力的支持被默认配置限制住了。这个场景在Android BSP开发里其实非常常见设备不是不识别SD卡而是没有完整发挥SD卡的能力。它涉及的不只是改一个开关而是要理清楚MMC子系统的分层结构、MTK host控制器的能力通告机制、以及设备树配置之间的配合。下面我用这次项目的完整排查和修改过程把SD卡驱动能力修改这件事从头到尾讲透适合正在调这类问题的系统工程师参考。1. 这个需求从哪来的能识别SD卡和能用满速之间差了一整套配置1.1 需求场景客户要的是卡插上就能满速干活当时接到的项目是一款行业定制设备硬件平台基于某款MTK 4G SoC系统版本是Android 8.1。客户提的需求很朴素要支持常见大容量存储卡读写速度不能比同类设备差。但实测结果让所有人都皱眉——识别倒是识别了512GB的卡也能看到容量可拷贝1GB的视频文件要花将近一分钟读写吞吐量只有20MB/s左右。这种问题最容易让人走弯路。第一反应是卡不行于是换卡、换读卡器、格式化不同文件系统一顿操作下来速度纹丝不动。又怀疑是板载走线或者屏蔽问题量了信号、换了卡座依然无解。最后静下心来看开机日志才发现真正的问题根本不在物理层而是在驱动的能力配置上。1.2 日志里的关键线索卡协商到了低速模式看dmesg时注意到一行不起眼的信息SD卡最终被识别成了SDXC但协商出来的传输模式停留在High Speed50MHz、3.3V信号而卡本身支持UHS-I控制器也声称支持更高的UHS模式。也就是说控制器和卡都有满血的能力结果在协商环节没有走到一起。这里要理解一个关键点SD卡驱动能力并不只是一个支持/不支持的开关而是一整套从物理层到协议层的配置组合。任何一个环节没对上系统就会以最保守、最兼容的模式运行。速度减半、容量显示异常往往都是这个保守兜底导致的。1.3 修改前必须确认的基线信息动代码之前先把项目涉及的基础信息理清楚系统版本Android 8.1对应内核版本要看具体BSP分支MTK平台在这个时期常见的是kernel 4.4和3.18两条线SD卡控制器的挂载路径需要确认当前应用的是mmc0还是mmc1节点不同产品走线不一样客户实际使用的卡规格最好拿同一批卡做测试样本避免拿一张卡测出新结果后换一张卡又回到旧问题。这些信息决定了后面改的是dts还是驱动源码也决定了排查方向。不建议拿着别人平台的修改经验直接套MTK不同分支、不同SoC的代码路径差异还是比较明显的。2. 先拆解SD卡驱动能力的层次MMC framework、MTK host与dts各自扮演什么角色2.1 Linux内核把SD卡驱动拆成了三层每一层都有自己该干的事要理解驱动能力修改得先知道能力这个词在代码里是怎么分布的。从Linux内核的角度看一张SD卡接入后工作流程大致是这样的MMC core层负责协议层面的管理——发命令、读CID、读CSD、协商工作模式host controller层负责实际执行传输包括时钟产生、命令发送、数据搬移而具体某块板卡支持什么功能则由设备树dts来声明。MTK平台的host控制器驱动就属于中间这一层。它向MMC core暴露自己支持的能力通过caps标志位MMC core拿到这些标志后再结合SD卡自身的能力取交集确定最终的工作模式。2.2 能力通告机制控制器和卡是怎么砍价的SD卡的速率协商可以理解成一场互相报价的过程。控制器先说我最高支持UHS-I SDR104200MHz卡也说我支持UHS-I最终双方取交集落到一个都认可的模式上。但如果控制器没有在caps里声明支持UHS-I或者dts里的对应属性没打开宿主控制器就只会给对方报一个很保守的价——最后协商结果就是High Speed 50MHz3.3V信号。开头那个卡能被识别但速度被腰斩的问题本质上就是控制器这个报价员身上少了一堆能力标签。2.3 Android 8.1这个版本的特殊性有必要单独说一下Android 8.1这个系统版本带来的影响。Android 8.1本身是用户态框架但存储、文件系统、用户态确认这些逻辑会直接影响SD卡最终能不能被完整使用。举个例子vold负责挂载和fstab解析vfat/exFAT的文件系统支持决定大容量卡能不能热插拔稳定使用。所以SD卡驱动能力修改并不是改完内核驱动就结束了。内核把卡识别成某个容量、协商出某种速率后面还要用户态的存储栈配合才能把能力真正落地到用户可以感知的文件读写速度上。提示同一个MTK平台Android 7和Android 9的修改位置就可能完全不同。先确认自己手里内核的具体版本再动手可以少走很多弯路。3. 第一步修改设备树dts里的SD卡能力开关与调参要点3.1 找到当前生效的mmc节点看清默认配置设备树dts在这里的作用相当于一张板级配置表。不同产品的SD卡走线、供电、引脚功能都可能不同dts就是把这些差异告诉内核的地方。先找到当前生效的mmc节点。通常在dts/dtsi里会有类似这样的结构mmc0 { status okay; pinctrl-names default, state_uhs; pinctrl-0 mmc0_default; pinctrl-1 mmc0_uhs; max-frequency 200000000; bus-width 4; cap-sd-highspeed; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; sd-uhs-sdr104; vmmc-supply mt6333_vmmc; vqmmc-supply mt6333_vqmmc; };注意这只是一个通用风格示意不同MTK分支的属性命名有差异。重点是先把当前节点里的配置读一遍搞清楚哪些能力是开的、哪些是没开的。3.2 常用能力属性速查与实际调整点下面这个表是这次项目里实际关注到的属性可以作为排查参考属性作用本次项目的处理max-frequency限制控制器时钟的最高频率从50MHz调到了200MHzbus-width数据线宽度SD卡一般为4bit保持不变cap-sd-highspeed打开High Speed模式默认已开启sd-uhs-sdr104打开UHS-I SDR104模式默认缺失需要补上sd-uhs-sdr50打开UHS-I SDR50模式默认缺失一并补上no-1-8-v强制不使用1.8V信号基线里带了需要移除vmmc-supply / vqmmc-supply卡供电和信号电压的稳压器检查供电范围是否满足1.8V/3.3V切换这个表格列出来的就是整个项目最核心的改动面。很多人只盯着max-frequency把频率调到200MHz就走了结果发现速度还是上不去因为少了后面几个UHS模式标志以及清除no-1-8-v控制器根本没进入UHS协商流程。3.3 max-frequency不是越高越好这里有实际教训先提醒一句不要一上来就把max-frequency调到顶。曾经试过直接把值改成400MHz结果开机后数据传输出现大量CRC错误写入越快越容易报错。原因不复杂MTK平台的SD host控制器和eMMC控制器可能复用部分时钟资源超频后信号完整性跟不上尤其是板级走线质量一般的情况下高速模式很容易翻车。比较稳妥的做法是先按SD卡协议允许的UHS-I上限200MHz来设跑稳了再根据实际信号质量评估是否需要降频。3.4 pinctrl和供电UHS模式必须有的配套真正的坑往往不在属性本身而在配置之间的关系。UHS-I模式要求信号电压从3.3V切换到1.8V这需要对应的pinctrl状态和vqmmc供电稳压器支持。检查点有三个pinctrl里要有state_uhs对应的引脚组不能只配defaultvqmmc-supply要能在3.3V和1.8V之间切换并且切换时序要满足SD卡规范如果dts里带了no-1-8-v那一切都白搭——直接禁用了电压切换。我们就是在这个环节被卡了很久。dts属性全对齐了电压切换还是不生效后来发现是pinctrl的state_uhs引脚配置里漏了一组时钟线。这种问题靠看dts文本很难一眼发现最好用设备树编译后的dump对一下实际生效的配置。4. 第二步修改host驱动里的caps标志、速率与电压切换4.1 host controller驱动在MTK平台上的位置和职责dts只是开关真正的能力通告代码在host controller驱动里。MTK平台的SD host驱动一般位于kernel/drivers/mmc/host/下文件名因分支而异但核心逻辑都是解析dts节点里的属性然后设置host的caps标志位。驱动里大致会有类似这样的逻辑/* host controller probe阶段能力解析 */ if (of_property_read_bool(np, sd-uhs-sdr104)) host-caps | MMC_CAP_UHS_SDR104; if (of_property_read_bool(np, sd-uhs-sdr50)) host-caps | MMC_CAP_UHS_SDR50; if (of_property_read_bool(np, sd-uhs-sdr25)) host-caps | MMC_CAP_UHS_SDR25;所以一个完整的修改路径是先改dts把能力属性加全再确认驱动确实把这些属性映射到了caps里。如果驱动本身就漏了解析代码dts改再多也没用。4.2 默认cap过高和过低都是坑这次还遇到一个很有意思的情况基线的host驱动里默认caps被设得比较高里面带了UHS-DDR50等模式的支持。按说能力高是好事但实际表现是——和某些卡协商时抽中了DDR50速度看着高却极不稳定大文件写入一段时间就报错。问题出在控制器的物理层并不完全具备DDR50模式需要的信号质量只是软件层面自认为支持。最后把不需要的模式从caps里清掉留下SDR104作为最高档才真正稳定下来。这件事给了一个重要教训能力通告不是越多越好必须和硬件实际信号质量匹配。多开的模式可能在某些卡上进得了协商却出不了稳定性能反而比少开更糟糕。4.3 电压切换时序UHS-I最容易失败的环节UHS-I的工作过程里MMC core会发送CMD11让卡切换信号电压到1.8V。这一步如果失败卡就自动退回到High Speed 3.3V模式速度直接回到50MHz。实际排查时主要看两个方向日志里有没有Voltage change timeout或者类似的错误vqmmc稳压器是否真实支持1.8V而不是只在dts里声明支持。硬件能力验证这一步比较花时间但必须做。我们最终是拿着示波器量了vqmmc在切换瞬间的电压波形确认掉电毛刺在允许范围内才断定软件配置没问题。注意如果最终产品有多个SKU共用一套BSP电压切换逻辑要特别小心验证。有些低成本板卡省掉了1.8V供电电路强行开启UHS反而会导致卡无法识别这时就需要用no-1-8-v属性的控制来区分产品分支。4.4 编译验证内核和bootimage都要一起更新驱动和dts修改完之后需要重新编译烧录bootimage。MTK平台一般通过mkimage或者整包编译脚本打包具体命令看分支文档。烧录完先别急着做性能测试先确认开机日志里有没有报错再往下走。5. 怎么验证从dmesg识别行到读写压测的全链路确认5.1 第一步看dmesg里的识别结果改完重新开机先看识别日志dmesg | grep -E mmc0|mmc1正常情况下应该能看到卡的类型从SDXC到UHS-I的识别信息。比如出现类似mmc0: new UHS-I SDXC card at address 0x0000aaaa如果看到的还是HS或者普通SDXC说明能力配置还没生效回头查dts和caps。5.2 第二步直接确认当前实际工作模式这一步很多工程师会忽略。识别日志说的是支持什么而实际协商结果要看sysfs调试节点cat /sys/kernel/debug/mmc0/ios正常进入SDR104模式时会显示类似clock: 200000000 Hz vdd: 21 (3.0 ~ 3.3 V) bus mode: 2 (push-pull) chip select: 0 (dont care) power mode: 2 (on) bus width: 2 (4 bits) timing spec: 9 (mmc_timing_sd_uhs_sdr104) signal voltage: 1 (1.8 V)注意不同内核分支对timing spec的编号有差异对照源码里的mmc_timing定义即可。5.3 第三步读写吞吐量实测协议层确认没问题再做用户可感知的读写速度验证。测试方法不复杂但要注意规范性# 写入1GB文件 dd if/dev/zero of/storage/XXXX/test.bin bs1M count1024 convfsync # 读出1GB文件 dd if/storage/XXXX/test.bin of/dev/null bs1M count1024更严谨一点可以用fio测试随机读写和IOPS。大文件顺序读写主要看吞吐量随机读写则更能反映文件系统和小IO的真实体验。5.4 验证结果对比以这个项目为例修改前后对比非常明显测试项修改前修改后顺序读21MB/s82MB/s顺序写18MB/s45MB/s协商模式High Speed 50MHzUHS-I SDR104 200MHz512GB容量显示32GB512GB数字变化很清楚但这只是单张卡的结果。SD卡兼容性问题最诡异的地方在于同一套BSP换一张卡可能又是另一种表现。所以验证阶段必须有多张卡交叉覆盖。6. 兼容性深水区容量误识别、热拔插抖动与低速卡回退问题6.1 512GB卡容量显示32GB问题出在哪一环这个现象在Android 8.1的MTK平台上并不罕见。SD卡容量信息主要靠CSD寄存器里的字段计算老内核或者驱动对CSD的容量上限计算可能存在cap超过这个上限就按最大值返回。另外即使内核识别出正确容量用户态挂载还会经过vold处理。如果exFAT/VFAT文件系统工具不认这么大分区也会出现容量异常。排查路径要分两步走内核层确认host的max_blk_count、max_req_size、max_seg_size这些参数没有被限制到32GB级别的瓶颈用户态确认exfat/fat格式化工具和vold的fstab配置能正确处理大分区。6.2 热拔插不稳定卡拔掉系统卡死或识别错乱这个坑在量产验证阶段出现得最多。插卡后系统读到错误中断或者拔卡瞬间系统卡死多数时候不是驱动速率问题而是card-detectCD引脚配置问题。排查重点cd-gpios对应的GPIO是否配了正确的上拉/下拉触发电平是否匹配中断处理里有没有做debounce处理机械抖动会导致中断风暴拔卡时vmmc的断电时序是否在协议允许的范围内。我们当时遇到的情况就是CD引脚中断在拔卡时反复触发导致mmc core每触发一次就重新扫描一次系统界面卡成狗。加了对齐去抖之后才消停。6.3 回归测试矩阵至少准备十张不同类型的卡SD卡能力的修改最怕的就是在办公室测得好好的到了客户现场翻车。原因是研发手里通常只有几张常见卡而客户现场会出现各种品牌、各种容量、各种协议版本的卡。一个可用的回归测试矩阵至少要覆盖卡类型容量是否支持UHS-I重点测试项品牌A32GB否普通模式读写品牌B128GB是UHS-I速度、热拔插品牌C256GB是大文件持续写入品牌D512GB是容量识别、exFAT品牌E1TB是容量识别、格式化每张卡都要跑一遍识别、格式化、大文件读写、随机读写、热拔插。只有整个矩阵通过这次修改才算真正完成。6.4 别忽略了卡本身的质量问题最后也说一个行业现状市面上所谓高速卡有相当一部分是扩容卡或者实际闪存芯片等级根本达不到标称速率。拿这样的卡做验证你会发现不管怎么改驱动速度都上不去甚至会误导你把问题定位到代码上。我的做法是在开始驱动调试前先用读卡器在电脑上跑一下官方工具或专门的存储检测工具确认卡本身没有质量问题。这一步能省掉后面无数个不可能的夜晚。调试SD卡驱动能力这件事看似就是改几个dts属性、调几个caps标志实际上每一层都有隐藏条件。硬件能力只是给你一个上限驱动的价值在于把这个上限安全、稳定地兑现出来而不是把所有模式都打开然后祈祷没有问题。修改的过程就像调一道菜备菜确认硬件规格、切配改dts、下锅改驱动、试菜压测每一步缺了都可能翻车。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑