MTK Android 设备去掉 Modem 完整方案。基线不是wifi-only的版本。

3 阅读6分钟

做 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.rcon 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 全开)45mA0%
关闭 Modem 服务35mA0%
关闭 XO_RFCK2A35mA0%

验证方法

# 检查 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/mt6771device/mediatek/mt6983
Kernel4.4/4.145.10
CCCIECCCIECCCI
PRODUCT_PACKAGES_REMOVE支持不支持,需 rc 加 disabled
硬件层处理不需要(老平台没有 srclken_rc)必须处理 srclken_rc + SPM mask
底电流优化空间中等很大(45mA→10mA)

总结

去 Modem 看似简单,实际涉及 4 个层面、十几个文件、至少 6 个容易踩的坑。核心经验:

  1. CUSTOM_MODEM 保留不删 — 否则 scatter 文件出错
  2. vold.post_fs_data_done 必须补 — 否则开不了机
  3. MTK_MULTIPLE_IMS_SUPPORT 设空不设 0 — 否则编译报错
  4. 省电要做到硬件层 — 关服务只是第一步,srclken_rc 和 SPM mask 才是关键
  5. PRODUCT_PACKAGES_REMOVE 不可靠 — 准备好 Plan B

本文作者专注 MTK 平台 Android BSP 定制开发,支持 MT6761/MT6762/MT6765/MT6785/MT8788/MT6789/MT6878/MT6983 等多平台。 如需完整方案或技术支持:

  • 淘宝店:深圳市海蓝光科技有限公司
  • 服务范围:MTK 方案定制 | MTK 核心板 | 系统/驱动开发