MTK8766 LK GPIO初始化状态设置分析
问题来源是M.2 Dongle的LED灯在kernel起来之前就亮了,kernel起来之后又初始化成熄灭状态。通过排查硬件规格书、GPIO表格,大概判定是前期软件初始化不正确造成的。通过观察串口打印的log,发现灯开始亮起来的瞬间是运行在lk中。
找到MTK 的LK代码路径
MT8766_A11_AP/vendor/mediatek/proprietary/bootable/bootloader/lk/
找到MTK的LK代码编译out目录
MT8766_A11_AP/out/target/product/tb8766p1_bsp_1g/obj/LK_OBJ/build-tb8766p1_bsp_1g/
再从out目录下的plarform目录确定当前编译的平台是mt6761,从而在对应的gpio配置输出函数中添加log
MT8766_A11_AP/vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6761/mt_gpio.c
S32 mt_set_gpio_mode_chip(u32 pin, u32 mode)
{
......
添加以下代码对改GPIO进行debug
if (pin == 174)
{
GPIOVER("============ fuck gpio ===============\n");
mdelay(1000);
}
return RSUCCESS;
}
通过log大概确定相关动作是在lk_dtb_init()中或者后面一点点
[254] [SBC] image dtbo auth init pass
[254] [SBC] image dtbo cert vfy pass(22 ms)
[255] [PROFILE] mmc read 1 blks in 0 ms: 8KB/s
[256] dtbo_total_len: 0x8a17
[257] [PROFILE] mmc read 69 blks in 1 ms: 34500KB/s
[258] [PROFILE] mmc read 1 blks in 0 ms: 8KB/s
[259] [SBC][oem] img auth pass
[259] [SBC] dtbo vfy pass(1 ms)
[260] dtbo_offset: 0x40
[260] [PROFILE] ::: lvl(3) load_dtbo_buffer takes 30 ms
[261] dtbo_size : 35287
[272] [PROFILE] ::: lvl(3) dtb_overlay takes 11 ms
[273] [PROFILE] ::: lvl(2) lk_dtb_init takes 100 ms
[275] [GPIO] mt_set_gpio_mode_chip: ============ fuck gpio ===============
[1278] [PROFILE] mmc read 32 blks in 2 ms: 8000KB/s
[1279] [LK_ENV]ENV of area 0 initialize sucess
[1280] [PROFILE] mmc read 32 blks in 1 ms: 16000KB/s
[1280] [LK_ENV]ENV SIG of area 1 is wrong
[1281] [LK_ENV]env area: 0
[1281] [LK_ENV]env:
[1281] [LK_ENV]md1_ccb_cap_gear=1
[1282] [LK_ENV]md1_ccb_gear_list=1(2,20);2(2,10);3(0,0);11(2,2);12(2,62)
[1283] [LK_ENV]env area: 1
[1283] [LK_ENV]no valid env
[1283] [PROFILE] ::: lvl(2) ENV init takes 7 ms
[1284] mblock_reserve-R start: 0x7f040000, sz: 0xdb0000 map:0 name:framebuffer
最终定位到以下调用关系
platform_early_init();
|
mt_gpio_set_default();
|
mt_gpio_set_default_chip();
观察mt_gpio_set_default,发现相关配置参数是从设备树中获取的,展开mt_gpio_set_default()函数中的mt_gpio_get_default_chip_from_dtb()调用,发现相关设备树节点名字是gpio@10005000,相关属性的名字是gpio_init_default。用adb pull /sys/firmware/fdt,反编译设备树确认存在这个属性和节点。
在kernel中过滤文本搜索gpio_init_default属性,发现并不存在与当前硬件相关的设备树文件!那么,猜测该属性应该是从别的设备树文件中合并进来的。再在代码中使用grep -nr gpio_init_default
全局过滤搜索,发现有以下文件与之相关。
./kernel-4.19/arch/arm64/boot/dts/mediatek/mt6779-evb.dts:604: gpio_init_default = <0 0 0 0 1 1 1>,
./vendor/mediatek/proprietary/tools/dct/python/obj/GpioObj.py:746: gen_str += '''\tgpio_init_default = '''
./vendor/mediatek/proprietary/tools/dct/python/obj/GpioObj.py:772: gen_str += '''\tgpio_init_default = '''
./vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/obj/GpioObj.py:710: gen_str += '''\tgpio_init_default = '''
./vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/obj/GpioObj.py:736: gen_str += '''\tgpio_init_default = '''
./vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6768/gpio_init.c:79:#define GPIO_DT_NODE_PROP_NAME "gpio_init_default"
./vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/mt_gpio_init.c:134:#define GPIO_DT_NODE_PROP_NAME "gpio_init_default"
./vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6761/mt_gpio_init.c:134:#define GPIO_DT_NODE_PROP_NAME "gpio_init_default"
./vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6785/gpio_init.c:79:#define GPIO_DT_NODE_PROP_NAME "gpio_init_default"
./vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6771/gpio_init.c:76:#define GPIO_DT_NODE_PROP_NAME "gpio_init_default"
./vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/GpioObj.py:710: gen_str += '''\tgpio_init_default = '''
./vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/GpioObj.py:736: gen_str += '''\tgpio_init_default = '''
打开与之相关的文件
vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/GpioObj.py
发现相关的python调用方法是fill_init_default_dtsiFile
,那么再全局过滤搜索这个方法名,发现有以下文件与之相关。
./vendor/mediatek/proprietary/tools/dct/python/obj/ChipObj.py:260: gen_str += gpioObj.fill_init_default_dtsiFile()
./vendor/mediatek/proprietary/tools/dct/python/obj/GpioObj.py:649: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/tools/dct/python/obj/GpioObj.py:744: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/tools/dct/python/obj/GpioObj.py:770: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/obj/ChipObj.py:224: gen_str += gpioObj.fill_init_default_dtsiFile()
./vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/obj/GpioObj.py:613: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/obj/GpioObj.py:708: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/obj/GpioObj.py:734: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/ChipObj.py:207: gen_str += gpioObj.fill_init_default_dtsiFile()
./vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/GpioObj.py:613: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/GpioObj.py:708: def fill_init_default_dtsiFile(self):
./vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/GpioObj.py:734: def fill_init_default_dtsiFile(self):
打开与之相关的文件
vendor/mediatek/proprietary/bootable/bootloader/lk/scripts/dct/obj/ChipObj.py
内容如下:
def gen_custDtsi(self):
log(LogLevel.info, 'Start to generate cust_dtsi file...')
fp = open(os.path.join(ModuleObj.get_genPath(), 'cust.dtsi'), 'w')
gen_str = ModuleObj.writeComment()
# if early porting, gen empty dtsi file for kernel
if self.__epFlag:
fp.write(gen_str)
fp.close()
return
#sorted_list = sorted(self.__objs.keys())
#for tag in sorted_list:
for tag in self.__objs.keys():
if cmp(tag, 'gpio') == 0:
gpioObj = self.create_obj(tag)
gen_str += ModuleObj.writeHeader(gpioObj.get_dtsiFileName())
gen_str += gpioObj.fill_mapping_dtsiFile()
gen_str += gpioObj.fill_init_default_dtsiFile()
else:
obj = self.create_obj(tag)
gen_str += ModuleObj.writeHeader(obj.get_dtsiFileName())
gen_str += obj.fill_dtsiFile()
gen_str += '''\n\n'''
fp.write(gen_str)
fp.close()
log(LogLevel.info, 'Generate cust_dtsi file successfully!')
可以从中判断出最终生成了cust.dtsi,全局搜索这个文件find -name cust.dtsi
,发现生成路径是
./out/target/product/tb8766p1_bsp_1g/obj/KERNEL_OBJ/arch/arm/boot/dts/tb8766p1_bsp_1g/cust.dtsi
打开后确认生成的文件存在gpio@10005000
节点和gpio_init_default
属性。但是目前又不能判断到底是从哪个文件中解析了配置,从而生成了最终的设备树文件。好在该方法中打印了log,再从Android的编译log中搜索Start to generate cust_dtsi file...
,发现以下内容:
[ 60% 688/1130] build out/target/product/tb8766p1_bsp_1g/obj/FAKE/treble_sepolicy_tests_27.0_intermediates/27.0_mapping.combined.cil
[ 60% 689/1130] build out/target/product/tb8766p1_bsp_1g/obj/KERNEL_OBJ/arch/arm/boot/dts/tb8766p1_bsp_1g/cust.dtsi
[DCT_INFO]: DWS file path is /home/123/workspace/MT8766_A11_AP/kernel-4.19/drivers/misc/mediatek/dws/mt6761/tb8766p1_bsp_1g.dws
[DCT_INFO]: Gen files path is /home/123/workspace/MT8766_A11_AP/out/target/product/tb8766p1_bsp_1g/obj/KERNEL_OBJ/arch/arm/boot/dts/tb8766p1_bsp_1g
[DCT_INFO]: Log files path is /home/123/workspace/MT8766_A11_AP/out/target/product/tb8766p1_bsp_1g/obj/KERNEL_OBJ/arch/arm/boot/dts/tb8766p1_bsp_1g
[DCT_INFO]: Parameter is cust_dtsi
[DCT_INFO]: chip id: MT6761
[DCT_INFO]: Chip ID : MT6761
[DCT_INFO]: Project Info: Merlot_Phone
[DCT_INFO]: Start to generate cust_dtsi file...
[DCT_INFO]: Generate cust_dtsi file successfully!
[ 61% 690/1130] //system/core/init:libinit static link libinit.a
[ 61% 691/1130] //system/core/init:libinit static link libinit.a
好家伙,绕了一圈原来是tb8766p1_bsp_1g.dws!