1、MTK平台概述:MTK芯片发展史、MTK平台架构(AP/BP/PMIC)、MTK驱动开发环境搭建(Linux + SDK)
1.1 MTK芯片发展史:从山寨机到5G时代的逆袭
做MTK驱动开发,首先得了解这家公司的来龙去脉。我个人觉得,MTK的发展史就是一部「中国手机芯片的奋斗史」。
早年间,MTK靠的是「Turnkey Solution」(交钥匙方案)起家。2000年代初,做手机门槛很高,厂商得自己搞定基带、射频、协议栈。MTK把基带芯片、软件协议栈、参考设计打包在一起,深圳华强北的小厂买回去,改个外壳就能卖。说白了,MTK降低了手机制造的门槛,也成就了当年的「山寨机」时代。
我记得2010年左右,MTK的MT6252方案几乎统治了功能机市场。那时候做驱动开发,主要跟NAND Flash、LCD屏、Camera打交道,代码量不大,但兼容性问题特别多。
进入智能机时代,MTK推出了MT6573、MT6575等芯片。说实话,早期智能机芯片发热大、兼容性差,被高通压着打。转折点在2013年的MT6589——四核Cortex-A7,功耗控制得不错,很多千元机都在用。我在项目中遇到过MT6589的USB驱动问题,当时调试了整整一周,最后发现是DMA buffer对齐的问题。
到了4G时代,MTK的Helio系列(P60、P90、G90T等)开始发力。尤其是Helio G90T,在游戏性能上跟高通骁龙730打得有来有回。现在5G时代,天玑系列(Dimensity 700/800/900/1000/1200/9000)已经站稳了中高端市场。天玑9000的Cortex-X2超大核加上台积电4nm工艺,性能完全不输骁龙8 Gen 1。
嗯,这里要注意:MTK芯片的驱动开发跟高通不太一样。MTK的代码风格偏「封闭」,很多底层寄存器操作封装在HAL层,不像高通那样直接暴露寄存器地址。你如果从高通转过来,刚开始会有点不习惯。
1.2 MTK平台架构:AP、BP、PMIC三件套
MTK芯片的内部架构,说白了就是三个核心模块:AP(应用处理器)、BP(基带处理器)、PMIC(电源管理芯片)。
| 模块 | 功能 | 典型芯片 | 驱动开发关注点 |
|---|---|---|---|
| AP | 运行Android/Linux系统,处理UI、应用、多媒体 | Cortex-A系列CPU + Mali GPU | LCD、TP、Camera、Sensor、WIFI/BT |
| BP | 处理蜂窝通信(2G/3G/4G/5G)、射频控制 | 独立的DSP核 + 硬件加速器 | Modem驱动、AT指令、射频校准 |
| PMIC | 电源管理、充电控制、电压调节 | MT6358、MT6360等 | 充电驱动、电量计、LDO控制 |
AP(应用处理器):这是咱们驱动开发的主战场。AP跑的是Linux内核 + Android系统,所有外设驱动(LCD、TP、Camera、Sensor、WIFI、BT、NFC等)都在这一侧。MTK的AP侧代码在kernel-4.14/4.19/5.10等版本中,驱动框架跟标准Linux内核基本一致,但加了很多MTK自己的HAL层封装。
BP(基带处理器):BP是MTK的看家本领。它有自己的实时操作系统(Nucleus RTOS或ThreadX),负责处理蜂窝协议栈。AP和BP之间通过「共享内存 + 中断」的方式通信,这个接口叫「CCCI」(Cross Core Communication Interface)。
我曾经在调试4G信号问题时,发现AP侧收不到BP上报的RSSI值。查了两天,最后定位到CCCI的ring buffer溢出。嗯,这种问题用printk很难复现,得用JTAG抓BP侧的log。
PMIC(电源管理芯片):MTK的PMIC通常跟AP/BP封装在一起,但物理上是独立芯片。PMIC负责给各个模块供电,比如CPU核心电压、DDR电压、IO电压等。驱动开发中,PMIC主要涉及充电驱动(Charger)、电量计(Fuel Gauge)、LDO控制。
你想想看,如果PMIC的LDO配置错了,外设可能上电时序不对,导致驱动初始化失败。我建议在调试新板子时,先用示波器量一下各路电源的波形,确认上电时序跟datasheet一致。
1.3 MTK驱动开发环境搭建:Linux + SDK
环境搭建这块,我踩过不少坑。下面直接给出一套经过验证的步骤。
1.3.1 硬件准备
- 开发板:MTK官方EVB(如MT8395 EVB)或第三方核心板
- 调试工具:USB转串口线(FT232/CP2102)、JTAG调试器(J-Link或Lauterbach)
- 电源:支持4.2V/3A的直流电源,别用USB供电,电流不够
1.3.2 软件环境
MTK官方推荐Ubuntu 18.04/20.04 LTS(64位)。我个人习惯用Ubuntu 20.04,兼容性最好。
# 安装必要依赖
sudo apt-get update
sudo apt-get install git-core gnupg flex bison build-essential \
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
libncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev \
libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig
# 安装repo工具(MTK用repo管理多个git仓库)
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
1.3.3 获取MTK SDK
MTK的SDK通常通过NDA(保密协议)获取。如果你在公司,找PM要「Release Package」。一般包含以下目录:
MTK_SDK/
├── kernel-4.19/ # Linux内核源码(MTK定制版)
├── vendor/mediatek/ # MTK HAL层驱动代码
├── device/mediatek/ # 板级配置(dts、defconfig)
├── bootable/bootloader/ # Preloader + LK(Little Kernel)
├── out/ # 编译输出目录
└── build/ # 编译脚本
避坑指南:我曾经因为SDK版本不对,编译出来的内核在板子上起不来。后来发现MTK的SDK跟内核版本是绑定的——kernel-4.19的SDK不能用在kernel-5.10上。所以拿到SDK后,先看README文件里的版本对应关系。
1.3.4 编译内核
# 配置内核(选择对应平台的defconfig)
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-android-
make mt8395_defconfig
# 编译内核
make -j$(nproc)
# 编译设备树
make dtbs
# 编译驱动模块
make modules
编译完成后,在 arch/arm64/boot/ 下会生成 Image.gz 和 dtb 文件。用fastboot烧录到板子上:
fastboot flash kernel Image.gz
fastboot flash dtb mt8395.dtb
fastboot reboot
1.3.5 调试技巧
我的调试三板斧:
- 串口log:MTK默认用UART0输出内核log,波特率921600。用minicom或putty连接,
dmesg -n 8打开所有log级别。 - 动态调试:在驱动代码里加
pr_debug(),然后echo 'file xxx.c +p' > /sys/kernel/debug/dynamic_debug/control动态开启。 - 抓取BP侧log:通过
cat /proc/mtk_logger获取Modem log,或者用MTK的「Catcher」工具(Windows版)。
注意:MTK的驱动代码里有很多宏开关,比如 CONFIG_MTK_xxx。编译前一定要确认defconfig里打开了对应的宏。我见过有人改了驱动代码,但忘了开宏,结果编译出来的内核根本没包含他的修改。
1.3.6 第一个驱动:Hello World
写一个最简单的MTK平台驱动,验证环境是否正常:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
static int mtk_hello_probe(struct platform_device *pdev)
{
pr_info("MTK Hello World: probe success!\n");
return 0;
}
static int mtk_hello_remove(struct platform_device *pdev)
{
pr_info("MTK Hello World: remove\n");
return 0;
}
static const struct of_device_id mtk_hello_of_match[] = {
{ .compatible = "mediatek,hello-world" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mtk_hello_of_match);
static struct platform_driver mtk_hello_driver = {
.probe = mtk_hello_probe,
.remove = mtk_hello_remove,
.driver = {
.name = "mtk_hello",
.of_match_table = mtk_hello_of_match,
},
};
module_platform_driver(mtk_hello_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MTK Hello World Driver");
然后在dts里添加节点:
hello_world: hello_world {
compatible = "mediatek,hello-world";
status = "okay";
};
编译烧录后,如果串口打印出 MTK Hello World: probe success!,说明环境搭建成功。
好了,第一章的内容就到这里。环境搭好了,后面咱们就可以开始写真正的外设驱动了。