MTK Android kernel6.1 新增驱动 Kconfig/Makefile/bzl 通用文档
1. 适用范围
本文档适用于正常 MTK Android 代码结构中的 kernel/kernel6.1 或 vendor kernel module 工程,说明新增一个 kernel driver 时通常需要修改哪些文件。
典型目录可能是:
text
kernel/kernel6.1/
kernel/kernel_device_modules-6.1/
device/mediatek/<project>/
vendor/mediatek/
不同项目目录名会有差异,实际以工程中的 BUILD.bazel、modules.bzl、*.config、vendor_dlkm.modules.load 为准。
如果你的代码是正常 MTK 单工程结构。实际修改时只看当前 lunch/build target 会引用哪些 config fragment、bzl target 和 module load 文件。
2. 总体原则
Android 12 之后的 MTK 项目通常是 GKI/Kleaf 架构。新增项目私有驱动时,推荐做成 vendor module:
text
CONFIG_XXX_DRIVER=m
这样会生成 .ko,打包到 vendor_dlkm,对 GKI 影响最小。
不推荐随意改:
text
kernel/kernel6.1/arch/arm64/configs/gki_defconfig
kernel/kernel6.1/modules.bzl 中的 GKI/common 模块列表
除非该驱动确实属于 GKI/common kernel 的一部分,并且已经确认不会破坏 ABI/KMI/VTS 要求。
3. 新增驱动需要改哪些东西
新增一个普通驱动通常涉及 5 类文件:
| 类别 | 作用 | 必须性 |
|---|---|---|
driver .c 文件 |
驱动实现 | 必须 |
Kconfig |
定义 CONFIG_XXX_DRIVER 配置项 |
必须 |
Makefile 或 Kbuild |
根据 CONFIG_XXX_DRIVER 编译目标文件 |
必须 |
| config fragment / defconfig | 打开 CONFIG_XXX_DRIVER=y/m |
必须 |
modules.bzl / BUILD.bazel / module list |
声明 .ko 产物进入 Bazel/Kleaf 构建 |
=m 时必须 |
vendor_dlkm.modules.load |
指定开机自动加载 .ko |
需要开机自动加载时必须 |
4. 推荐路径:做成 vendor module
4.1 放置驱动源码
如果是项目私有驱动,优先放到 vendor kernel module 目录,例如:
text
kernel/kernel_device_modules-6.1/drivers/misc/xxx_driver.c
或项目已有的 vendor driver 目录:
text
kernel/kernel_device_modules-6.1/drivers/<subsystem>/xxx/
如果你的工程没有单独的 kernel_device_modules-6.1,而是把 vendor driver 也放在 kernel/kernel6.1 里,则可以放到:
text
kernel/kernel6.1/drivers/misc/xxx_driver.c
但仍建议以 CONFIG_XXX_DRIVER=m 的方式编成 vendor module。
4.2 修改 Kconfig
示例:驱动放在 drivers/misc/xxx_driver.c。
修改:
text
kernel/kernel6.1/drivers/misc/Kconfig
或:
text
kernel/kernel_device_modules-6.1/drivers/misc/Kconfig
追加:
kconfig
config XXX_DRIVER
tristate "XXX driver"
depends on OF
help
Enable XXX driver for this MTK platform.
如果驱动有单独目录:
text
drivers/misc/xxx/Kconfig
drivers/misc/xxx/Makefile
drivers/misc/xxx/xxx_driver.c
则上层 drivers/misc/Kconfig 加:
kconfig
source "drivers/misc/xxx/Kconfig"
4.3 修改 Makefile/Kbuild
单文件驱动:
makefile
obj-$(CONFIG_XXX_DRIVER) += xxx_driver.o
目录形式驱动:
makefile
obj-$(CONFIG_XXX_DRIVER) += xxx/
子目录 drivers/misc/xxx/Makefile:
makefile
obj-$(CONFIG_XXX_DRIVER) += xxx_driver.o
如果一个驱动由多个 .c 文件组成:
makefile
obj-$(CONFIG_XXX_DRIVER) += xxx_driver.o
xxx_driver-y += xxx_core.o
xxx_driver-y += xxx_hw.o
xxx_driver-y += xxx_sysfs.o
当 CONFIG_XXX_DRIVER=m 时,最终模块名是:
text
xxx_driver.ko
5. 修改内核配置
5.1 不要改生成出来的 .config
不要直接改:
text
out/.../.config
.config 是编译时生成文件,重新编译后会被覆盖。
应该改源码中的 defconfig 或 config fragment。
5.2 优先找 vendor/project config
在工程根目录搜索:
sh
find kernel device vendor \( -name "*defconfig" -o -name "*.config" \)
rg -n "CONFIG_.*=" kernel device vendor -g "*defconfig" -g "*.config"
常见位置包括:
text
kernel/kernel_device_modules-6.1/arch/arm64/configs/*.config
kernel/kernel_device_modules-6.1/arch/arm64/configs/*defconfig
kernel/kernel6.1/arch/arm64/configs/*.config
device/mediatek/<project>/*.config
device/mediatek/<project>/*defconfig
项目私有驱动推荐加到 vendor/project config:
text
CONFIG_XXX_DRIVER=m
不建议加到:
text
kernel/kernel6.1/arch/arm64/configs/gki_defconfig
5.3 如何定位当前产品真正用到的 config
正常 MTK 工程里,不同产品会复用很多 config fragment。最稳的方法是从 build 配置反查当前 target。
先搜当前产品名或 platform 名:
sh
rg -n "<project>|<platform>|gki_defconfig|defconfig_fragments|DEFCONFIG|KERNEL_CONFIG" device vendor kernel
再看 bzl/build config 中类似字段:
text
build_config
defconfig
defconfig_fragments
pre_defconfig_fragments
post_defconfig_fragments
kernel_config
最终原则:
- 当前 build target 引用的 fragment,修改才会生效。
- 没被当前 target 引用的
*.config,改了也不会进入最终.config。 - 同一个
CONFIG_XXX_DRIVER如果在多个 fragment 出现,后合入的 fragment 可能覆盖前面的值。
5.4 =m 和 =y 怎么选
| 配置 | 结果 | 是否生成 .ko |
是否需要改 bzl/module list | 典型用途 |
|---|---|---|---|---|
CONFIG_XXX_DRIVER=m |
编译成模块 | 是 | 是 | 项目私有驱动,推荐 |
CONFIG_XXX_DRIVER=y |
编进 kernel image | 否 | 通常不需要 | 很早期必须可用的核心驱动 |
| 不配置 | 不编译 | 否 | 否 | 功能关闭 |
推荐:
text
CONFIG_XXX_DRIVER=m
只有满足以下情况才考虑 =y:
- 驱动必须在 very early boot 阶段可用。
- 根文件系统、启动链路或关键电源链路依赖它。
- 已确认不会破坏 GKI/KMI/VTS 要求。
6. 修改 bzl / BUILD.bazel
6.1 为什么 =m 还要改 bzl
Kconfig/Makefile 只决定 .ko 能不能被编出来。
Bazel/Kleaf 工程还需要知道这个 .ko 是目标产物,否则可能出现:
text
CONFIG 已打开,但 out/dist 或 vendor_dlkm 里没有 xxx_driver.ko
所以 CONFIG_XXX_DRIVER=m 时,需要把 .ko 加进对应的 module list。
6.2 先找到项目实际使用的 bzl
搜索:
sh
rg -n "module_outs|module_implicit_outs|modules.bzl|vendor_dlkm|MODULES_LIST" kernel device vendor
常见文件:
text
kernel/kernel6.1/modules.bzl
kernel/kernel6.1/BUILD.bazel
kernel/kernel_device_modules-6.1/modules.bzl
kernel/kernel_device_modules-6.1/BUILD.bazel
device/mediatek/<project>/*.bzl
6.3 加到 vendor 模块列表
假设生成的模块是:
text
drivers/misc/xxx_driver.ko
则在 vendor module list 中加入:
python
_VENDOR_MODULES_LIST = [
# existing modules
"drivers/misc/xxx_driver.ko",
]
实际变量名可能不是 _VENDOR_MODULES_LIST,也可能叫:
text
_MTK_VENDOR_MODULES
_DEVICE_MODULES_LIST
_VENDOR_DLKM_MODULES_LIST
module_outs
module_implicit_outs
原则是:加到 vendor/device module list,不要加到 common GKI module list。
6.4 module_outs 示例
如果工程使用 BUILD.bazel 中的 module_outs:
python
kernel_build(
name = "kernel_aarch64",
outs = [
"Image",
],
module_outs = [
# existing modules
"drivers/misc/xxx_driver.ko",
],
)
如果是 vendor kernel module target:
python
kernel_module(
name = "xxx_driver",
srcs = [
"drivers/misc/xxx_driver.c",
],
outs = [
"xxx_driver.ko",
],
kernel_build = "//kernel/kernel6.1:kernel_aarch64",
)
具体写法以你项目已有 target 为准,新增驱动时优先照抄同目录已有驱动的写法。
6.5 不要加错列表
一般不要加到类似下面这种 common/GKI 列表:
python
_COMMON_GKI_MODULES_LIST = [
...
]
项目私有驱动应该加到 vendor/device list。
7. 修改 modules.load
如果驱动需要开机自动加载,需要加入 vendor module load 文件。
搜索:
sh
find device vendor kernel -name "*modules.load*"
rg -n "vendor_dlkm.modules.load|modules.load" device vendor kernel
常见文件:
text
device/mediatek/<project>/vendor_dlkm.modules.load
device/mediatek/<project>/vendor_dlkm.modules.load.recovery
vendor/mediatek/proprietary/.../vendor_dlkm.modules.load
追加:
text
xxx_driver.ko
注意:
- 加到
modules.load只是自动加载。 - 不加也可能可以手动
insmod。 - 如果驱动需要依赖其他
.ko,依赖模块要先加载,或者依赖modprobe/modules.dep处理。
8. Device Tree 配置
如果驱动是 platform driver,通常还需要 DTS 节点。
驱动中:
c
static const struct of_device_id xxx_of_match[] = {
{ .compatible = "mediatek,xxx-driver" },
{ }
};
MODULE_DEVICE_TABLE(of, xxx_of_match);
DTS 中:
dts
xxx_driver: xxx-driver {
compatible = "mediatek,xxx-driver";
status = "okay";
};
如果使用 GPIO/IRQ/clock/regulator,需要在 DTS 中补充:
dts
xxx_driver: xxx-driver {
compatible = "mediatek,xxx-driver";
xxx-gpios = <&pio 10 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&pio>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
status = "okay";
};
如果 DTS 节点 status = "disabled",即使 .ko 已加载,也不会 probe 该设备。
9. 编译后检查
9.1 检查最终 .config
sh
find out -name ".config" -exec grep -H "CONFIG_XXX_DRIVER" {} \;
期望:
text
CONFIG_XXX_DRIVER=m
如果没有出现,说明 config fragment 没被当前 target 使用。
9.2 检查 .ko 是否生成
sh
find out -name "xxx_driver.ko"
期望能找到:
text
out/.../drivers/misc/xxx_driver.ko
out/.../dist/vendor_dlkm/lib/modules/xxx_driver.ko
如果源码目录里生成了,但 dist/vendor_dlkm 里没有,通常是 bzl/module list 没加。
9.3 检查模块是否进入 vendor_dlkm
sh
find out -path "*vendor_dlkm*" -name "xxx_driver.ko"
如果找不到,检查:
text
modules.bzl / BUILD.bazel
vendor_dlkm.modules.load
BOARD_VENDOR_KERNEL_MODULES
BOARD_VENDOR_RAMDISK_KERNEL_MODULES
具体哪个生效取决于项目构建方式。
10. 板端验证
刷机后检查:
sh
adb root
adb shell lsmod | grep xxx
adb shell dmesg | grep -i xxx
adb shell find /vendor_dlkm/lib/modules -name "xxx_driver.ko"
如果没有自动加载:
sh
adb shell insmod /vendor_dlkm/lib/modules/xxx_driver.ko
adb shell dmesg | tail
如果 insmod 成功但没有 probe:
- 检查 DTS
compatible是否和驱动匹配。 - 检查 DTS
status是否为"okay"。 - 检查驱动是否注册了
platform_driver/i2c_driver/spi_driver。 - 检查依赖的 GPIO/IRQ/clock/regulator 是否获取失败。
11. 常见问题
11.1 CONFIG 打开了,但没有 .ko
可能原因:
Makefile没有加obj-$(CONFIG_XXX_DRIVER)。Kconfig没有被上层source。- 改错 config fragment,当前 build target 没用到。
depends on条件不满足,Kconfig 自动把配置关掉。
11.2 .ko 编出来了,但 vendor_dlkm 里没有
可能原因:
- 没有加到
modules.bzl/BUILD.bazel的 vendor module list。 - 加到了 GKI/common list,实际 vendor target 没使用。
- 只加了
modules.load,但没有加到 module outputs。
11.3 .ko 在 vendor_dlkm 里,但开机没加载
可能原因:
- 没加到
vendor_dlkm.modules.load。 - 模块依赖没先加载。
- 模块签名或版本不匹配。
init阶段没有加载对应分区的 modules.load。
11.4 模块加载了,但驱动没有 probe
可能原因:
- DTS 没有节点。
- DTS
compatible字符串不匹配。 - DTS
status = "disabled"。 - 设备挂在 I2C/SPI/platform,但 driver 类型写错。
- probe 中获取 GPIO/clock/regulator 失败后返回错误。
12. 最小修改清单
以 drivers/misc/xxx_driver.c、CONFIG_XXX_DRIVER=m 为例:
text
1. 新增驱动:
kernel/kernel6.1/drivers/misc/xxx_driver.c
或 kernel/kernel_device_modules-6.1/drivers/misc/xxx_driver.c
2. 修改 Kconfig:
drivers/misc/Kconfig
3. 修改 Makefile:
drivers/misc/Makefile
4. 修改 vendor/project config:
CONFIG_XXX_DRIVER=m
5. 修改 vendor module bzl/list:
drivers/misc/xxx_driver.ko
6. 修改 vendor_dlkm.modules.load:
xxx_driver.ko
7. 如需要自动 probe,修改 DTS:
compatible = "mediatek,xxx-driver";
status = "okay";
13. 推荐检查命令
sh
# 找 config fragment
find kernel device vendor \( -name "*defconfig" -o -name "*.config" \)
# 找 bzl/module list
rg -n "module_outs|module_implicit_outs|MODULES_LIST|vendor_dlkm" kernel device vendor
# 找 modules.load
find device vendor kernel -name "*modules.load*"
# 编译后检查 CONFIG
find out -name ".config" -exec grep -H "CONFIG_XXX_DRIVER" {} \;
# 编译后检查 ko
find out -name "xxx_driver.ko"
# 板端检查
adb shell lsmod | grep xxx
adb shell dmesg | grep -i xxx
14. 结论
MTK Android kernel6.1 新增项目私有驱动时,推荐路径是:
text
驱动源码 + Kconfig + Makefile
↓
vendor/project config 中 CONFIG_XXX_DRIVER=m
↓
vendor module bzl/module_outs 中加入 xxx_driver.ko
↓
vendor_dlkm.modules.load 中加入 xxx_driver.ko
↓
DTS 节点 status = "okay"
核心判断:
CONFIG_XXX_DRIVER=m时,一定要关心.ko是否进入 bzl/module list 和vendor_dlkm。CONFIG_XXX_DRIVER=y时,通常不用加.kolist,但会改 kernel image,需谨慎。- 项目私有驱动不要优先改
gki_defconfig和 GKI/common module list。