做 WiFi-Only 的平板、PDA、扫描仪、工控设备?MTK 平台去掉 Modem 没你想的那么简单。 本文基于 MT8788 和 MT6983 两个平台的实战经验,总结了完整的去 Modem 方案和踩坑记录。
为什么要去 Modem
很多 MTK 方案的定制设备并不需要 4G 通信功能:WiFi-Only 平板、工业 PDA、手持扫描仪、OCR 摄像头等。但 MTK BSP 默认开启完整的 Modem 支持,不去掉会导致:
- 功耗浪费:Modem 子系统常驻运行,ccci_mdinit、mtkrild 等进程占用资源
- 26M 时钟无法关闭:suspend 时 Modem 硬件请求 XO 时钟,底电流居高不下
- logcat 刷屏:CCCI audio 驱动反复尝试打开
/dev/ccci_aud失败,每次 200 条 warning - 启动变慢:Modem 初始化耗时数秒
我在一个 MT6983 项目上,完整去掉 Modem 后底电流从 45mA 降到了 10mA。
去 Modem 的 4 个层面
这是最关键的认知:去 Modem 不是改一个配置就完事的,需要从 4 个层面逐层处理:
第1层:编译配置层 (ProjectConfig.mk)
↓ 关闭 Modem 编译开关
第2层:服务层 (init.rc / device.mk)
↓ 阻止 Modem 相关服务启动
第3层:内核驱动层 (defconfig / DTS)
↓ 禁用 CCCI/ECCCI 驱动和 Modem 设备节点
第4层:硬件信号层 (srclken_rc / SPM)
↓ 屏蔽 Modem 硬件域的时钟和电源请求
很多人只做了第 1、2 层就以为完成了,结果功耗降不下来。第 3、4 层才是真正省电的关键。
第 1 层:编译配置 (ProjectConfig.mk)
需要修改的核心配置项:
# Modem 支持关闭
MTK_MD1_SUPPORT = 0
MTK_MD2_SUPPORT = 0
MTK_NUM_MODEM_PROTOCOL = 0
MTK_MULTI_SIM_SUPPORT = 0
MTK_ECCCI_C2K = no
# IMS/VoLTE 关闭(依赖 Modem,必须一起关)
MTK_IMS_SUPPORT = no
MTK_VOLTE_SUPPORT = no
MTK_WFC_SUPPORT = no
MTK_VILTE_SUPPORT = no
MTK_VIWIFI_SUPPORT = no
MTK_CT_VOLTE_SUPPORT = no
MTK_EPDG_SUPPORT = no
# Modem 日志和监控
MTK_MDLOGGER_SUPPORT = no
MTK_MODEM_MONITOR_SUPPORT = no
# WiFi Only 标记
MTK_TB_WIFI_3G_MODE = WIFI_ONLY
MTK_BUILD_IGNORE_IMS_REPO = yes
踩坑 1:CUSTOM_MODEM 不能删
很多人第一反应是把 CUSTOM_MODEM 清空。千万别这样做! 编译系统依赖这个值生成 scatter 文件和分区布局。清空后 md1img.img 不生成,刷机工具会报错。
正确做法:保留 CUSTOM_MODEM 原值,只通过上面的配置项禁用 Modem 功能。
踩坑 2:MTK_MULTIPLE_IMS_SUPPORT 要设空,不是设 0
# 错误!ifneq (,0) 仍然为真,会触发依赖检查报错
MTK_MULTIPLE_IMS_SUPPORT = 0
# 正确!空字符串才能跳过检查
MTK_MULTIPLE_IMS_SUPPORT =
踩坑 3:MTK_SINGLE_BIN_MODEM_SUPPORT 不能改
改为 no 会导致 ptgen.pl 在 scatter 里新增 md1dsp 分区,与原始 scatter 不一致,量产烧录会出错。
踩坑 4:RAT_CONFIG 要保留原值
CUSTOM_MODEM 还在时,依赖检查脚本 android_dep_rule.mak 强制要求 MTK_PROTOCOL1_RAT_CONFIG 非空。清空会编译报错。
第 2 层:服务层 (init.rc / device.mk)
device.mk 注释 Modem 包
# 注释掉以下 PRODUCT_PACKAGES
# PRODUCT_PACKAGES += ccci_mdinit
# PRODUCT_PACKAGES += ccci_fsd
# PRODUCT_PACKAGES += ccci_rpcd
# PRODUCT_PACKAGES += md_ctrl
同时注释 Modem RC 文件的拷贝:
# PRODUCT_COPY_FILES += .../init.modem.rc:$(MTK_TARGET_VENDOR_RC)/init.modem.rc
init.rc 注释 import
# import ${ro.vendor.rc}init.modem.rc
# import ${ro.vendor.rc}init.volte.rc
# import ${ro.vendor.rc}init.mal.rc
踩坑 5:vold.post_fs_data_done 必须补上!
init.modem.rc 里有一行 setprop vold.post_fs_data_done 1。注释 import 后这行也没了,会导致设备无法开机(PQ HAL、display 等服务全部卡死等待这个属性)。
必须在 init.mt67xx.rc 的 on post-fs-data 中补上:
on post-fs-data
# Modem RC removed, must set this here
setprop vold.post_fs_data_done 1
这是最容易被忽略、后果最严重的一个坑。
踩坑 6:PRODUCT_PACKAGES_REMOVE 不一定生效
在某些 MTK Android 12 版本上,PRODUCT_PACKAGES_REMOVE += ccci_mdinit 写了也不生效。vendor 分区的 rc 文件照样被打包进去。
解决办法:直接在 vendor rc 源文件里给服务加 disabled:
service ccci_mdinit /vendor/bin/ccci_mdinit 0
user system
group radio system
oneshot
disabled # 加这一行
补充:CCCI Audio 日志刷屏
去掉 Modem 后 Audio HAL 会反复尝试打开 /dev/ccci_aud 失败,每次重试 200 次、打印 200 条 warning。
修改 SpeechMessengerNormal.cpp,把 k_max_try_cnt 从 200 改为 3,重试 log 级别从 ALOGW 降为 ALOGV。不影响正常音频功能。
第 3 层:内核驱动层
defconfig 禁用 ECCCI
# CONFIG_MTK_ECCCI_DRIVER is not set
# CONFIG_MTK_ECCCI_C2K is not set
CONFIG_MTK_MD1_SUPPORT=0
注意:CONFIG_MTK_MD1_SUPPORT 必须写 =0,不能写 is not set。MTK 的 check_kernel_config.py 用整数比较,格式不对会报 sync 错误。
DTS 禁用 CCCI 节点
ccci_ccif {
compatible = "mediatek,ccci_ccif";
status = "disabled"; /* 加这行 */
};
ccci_md_scp {
compatible = "mediatek,ccci_md_scp";
status = "disabled";
};
第 4 层:硬件信号层(省电的关键!)
这一层是大多数文章不会告诉你的。
即使 Modem 服务全关了、CCCI 驱动也禁用了,你会发现 suspend 时 26M 时钟依然无法关闭。原因是 SoC 内部 Modem 硬件域的信号线(SRCCLKENA 等)是硬件固定连线,不受软件层是否运行影响。
需要额外处理:
srclken_rc 移除 md1 通道
DTS 里的 srclken-rc 节点有 subsys-ctl 列表,包含 md1。移除它:
/* 从 subsys-ctl 列表移除 "md1" */
/* 注释 md1-ctl = "XO_RFCK2A" */
clkbuf 关闭 RFCK2A support
/* xo-buf-support: RFCK2A 从 1 改为 0 */
做完这一步后,实测效果:
| 阶段 | 底电流 | 26M_off_pct |
|---|---|---|
| 初始(Modem 全开) | 45mA | 0% |
| 关闭 Modem 服务 | 35mA | 0% |
| 关闭 XO_RFCK2A | 35mA | 0% |
验证方法
# 检查 Modem 服务是否还在运行
adb shell ps -A | grep -i "ccci\|rild\|md_ctrl"
# 应无输出
# 检查关键属性
adb shell getprop vold.post_fs_data_done # 应为 1
adb shell getprop ro.radio.noril # 应为 yes
# 检查 CCCI 驱动是否加载
adb shell cat /proc/ccci_dump 2>&1
# 应报错 No such file
# 检查 suspend 后 26M 关闭率
# kernel log 中搜索 26M_off_pct,应 > 0
不同平台的差异
| 项目 | MT8788 (Android 9) | MT6983 (Android 12) |
|---|---|---|
| 平台目录 | device/mediatek/mt6771 | device/mediatek/mt6983 |
| Kernel | 4.4/4.14 | 5.10 |
| CCCI | ECCCI | ECCCI |
| PRODUCT_PACKAGES_REMOVE | 支持 | 不支持,需 rc 加 disabled |
| 硬件层处理 | 不需要(老平台没有 srclken_rc) | 必须处理 srclken_rc + SPM mask |
| 底电流优化空间 | 中等 | 很大(45mA→10mA) |
总结
去 Modem 看似简单,实际涉及 4 个层面、十几个文件、至少 6 个容易踩的坑。核心经验:
- CUSTOM_MODEM 保留不删 — 否则 scatter 文件出错
- vold.post_fs_data_done 必须补 — 否则开不了机
- MTK_MULTIPLE_IMS_SUPPORT 设空不设 0 — 否则编译报错
- 省电要做到硬件层 — 关服务只是第一步,srclken_rc 和 SPM mask 才是关键
- PRODUCT_PACKAGES_REMOVE 不可靠 — 准备好 Plan B
本文作者专注 MTK 平台 Android BSP 定制开发,支持 MT6761/MT6762/MT6765/MT6785/MT8788/MT6789/MT6878/MT6983 等多平台。 如需完整方案或技术支持:
- 淘宝店:深圳市海蓝光科技有限公司
- 服务范围:MTK 方案定制 | MTK 核心板 | 系统/驱动开发