1:客户需求

使用相同的固件rom包,在设备启动过程中,根据硬件设计的一个或多个gpio引脚的高低电平来选择使用不同的设备树配置。

2:修改思路

在qcom平台上,存在有几十个设备树文件, 这些设备树中都会包含多组 board-id, plateform-id, pmic-id 等信息, 用于与之比较的是在lk中读取到的设备信息。

现在新建立一个新的设备树文件,就要保证 在匹配过程中,能够有条件让我们添加的设备树被正确的识别并匹配到。

所以修改的思路是,在lk读取设备信息之后, 根据gpio的状态 去主动的修改 这些用于匹配的设备信息中的某些内容,用于匹配到新添加的设备树。

3:过程分析

简析lk驱动过程中,有关于设备树匹配的部分,这有助于理解 设备树识别,匹配的规则,方便我们有效的完成这个修改方案。

从lk开始的部分 Kmain函数开始:

/* called from crt0.S */
void kmain(void)
|->platform_early_init(void)
|	->board_init();
|		->platform_detect();
|			->wirite struct board_data
|				struct board_data {
|				uint32_t platform;
|				uint32_t foundry_id;
|				uint32_t platform_version;
|				uint32_t platform_hw;
|				uint32_t platform_subtype;
|				uint32_t target;
|				uint32_t baseband;
|				struct board_pmic_data pmic_info[MAX_PMIC_DEVICES];
|				uint32_t platform_hlos_subtype;
|
|
|->bootstrap2
|	->apps_init();
|		->aboot_init();
|			->normal_boot:
|			  boot_linux_from_mmc();
|				->dev_tree_appended
|					->...
|						while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
|							fdt_check_header
|							fdt_check_header_ext
|							dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
|						}
|							platform_dt_match_best
|								->best_match_dt_entry
|					  ...
};

以上的while循环中,会把镜像中打包的每个设备设备树文件取出,进行检测及解析最后进行匹配的工作,将匹配上的设备树加入到链表中,供后面再比较选择。

分析下dev_tree_compatible:

dev_tree_compatible
	->root_offset = fdt_path_offset(dtb, "/");
	  prop = fdt_getprop(dtb, root_offset, "model", &len);
	  pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
	  board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
	  	->
		......
		/* Extract board data from DTB */
			for(i = 0 ; i < board_data_count; i++) {
				board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
				board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
				if (board_data[i].platform_subtype == 0)
					board_data[i].platform_subtype =
					fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
				len_board_id -= sizeof(struct board_id);
				board_prop += sizeof(struct board_id);
			}
		/* Extract platform data from DTB */
			for(i = 0 ; i < msm_data_count; i++) {
				platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
				platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
				len_plat_id -= sizeof(struct plat_id);
				plat_prop += sizeof(struct plat_id);
			}
			if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
		/* Extract pmic data from DTB */
				for(i = 0 ; i < pmic_data_count; i++) {
					pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
					pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
					pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
					pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
					len_pmic_id -= sizeof(struct pmic_id);
					pmic_prop += sizeof(struct pmic_id);
				}
		......
		platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) 		
		}
	}

以上是简单的挑选出了对每个设备树提取数据的过程,最后会通过platform_dt_absolute_match与之前在platform_detect 读取到的 内容做比较。

-> platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) 
	if(
		(cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
		(cur_dt_hw_platform == board_hardware_id()) &&
		(cur_dt_hw_subtype == board_hardware_subtype()) &&
		(cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
		(cur_dt_entry->soc_rev <= board_soc_version()) &&
		((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
		((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
		((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
		((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
		((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) 
		{
		dt_node_tmp = dt_entry_list_init();
		memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));

		dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
			dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
			dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
			dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
			dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
			dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
		insert_dt_entry_in_queue(dt_list, dt_node_tmp);
		return 1;
	}
	return 0;

这里可以看出在筛选阶段,需要 board_platform_id,board_hardware_id,board_hardware_subtype,target_get_hlos_subtype,board_soc_version,board_target_id,board_pmic_target 都能满足对应的条件才能够完成匹配

从实际打印的log中来看,其实在设备上,这个阶段已经将设备树筛选完了, 下面截取一些,未被选中的 设备树在匹配过程中的判断信息:

[8150] [8150] Found an appended flattened device tree (Qualcomm Technologies, Inc. MSM8909-PM8909 MTP - 245 8 256 0x0)
[8160] [8160] cur_dt_msm_id000000f5, (board_platform_id() & 0x0000ffff)000000f5
[8170] [8170] cur_dt_hw_platform00000008, board_hardware_id00000008
[8180] [8180] cur_dt_hw_subtype00000000, board_hardware_subtype00000001
[8180] [8180] Device tree's msm_id doesn't match the board: <245 8 0 0x100> != <245 8 1 0x20000>
[8190] [8190] Found an appended flattened device tree (Qualcomm Technologies, Inc. MSM8909-PM8909 MTP - 245 8 256 0x0)
[8200] [8200] cur_dt_msm_id000000f5, (board_platform_id() & 0x0000ffff)000000f5
[8210] [8210] cur_dt_hw_platform00000008, board_hardware_id00000008
[8210] [8210] cur_dt_hw_subtype00000000, board_hardware_subtype00000001
[8220] [8220] Device tree's msm_id doesn't match the board: <245 8 0 0x100> != <245 8 1 0x20000>

这里可以发现,MSM8909-PM8909 MTP 这个设备树未匹配成功,从我添加的log中可以发现,是cur_dt_hw_subtype 不等于 board_hardware_subtype 导致了,匹配失败

这里也可以确定,如果想要匹配成功,board_hardware_subtype 就需要为 0 ,下面给出 在platform_detect 阶段读到内容log,与正确匹配时的log##

->platform_detect 
[6300] [6300] sc20 boardinfo as fllow:
 baseband:0
 platform:246
 foundry_id:0
 platform_hlos_subtype:0
 platform_hw:8
 platform_subtype:0
 platform_version:20000
 target:10008
[6320] [6320] sc20 pmicinfo :3 as fllow:
[6320] [6320] pmic0-----
[6320] [6320]
 pmic_target:1010d
 pmic_type:1000d
 pmic_version:10001
[10680] [10680] Found an appended flattened device tree (Qualcomm Technologies, Inc. MSM8909-PM8909 1GB MTP ST - 246 8 0 0x0)
[10690] [10690] cur_dt_msm_id000000f6, (board_platform_id() & 0x0000ffff)000000f6
[10700] [10700] cur_dt_hw_platform00000008, board_hardware_id00000008
[10700] [10700] cur_dt_hw_subtype00000000, board_hardware_subtype00000000
[10710] [10710] cur_dt_hlos_ddr00000000, (target_get_hlos_subtype() & 0x700)00000000
[10720] [10720] cur_dt_entry->soc_rev00000000, board_soc_version00020000
[10720] [10720] (cur_dt_entry->variant_id & 0x00ffff00)00000000, (board_target_id() & 0x00ffff00)00010000
[10730] [10730] (cur_dt_entry->pmic_rev[0] & 0x00ffff00)00010000, (board_pmic_target(0) & 0x00ffff00)00010100
[10740] [10740] (cur_dt_entry->pmic_rev[1] & 0x00ffff00)00000000, (board_pmic_target(1) & 0x00ffff00)00000000
[10750] [10750] (cur_dt_entry->pmic_rev[2] & 0x00ffff00)00000000, (board_pmic_target(2) & 0x00ffff00)00000000
[10760] [10760] (cur_dt_entry->pmic_rev[3] & 0x00ffff00)00000000, (board_pmic_target(3) & 0x00ffff00)00000000
[10780] [10780] Add DTB entry 246/00000008/0x00000000/0/1000d/0/0/0/90a9c834/29307
[10780] [10780] Device tree exact match the board: <246 8 0 0x0> == <246 8 0 0x20000>

最后在对所有的设备树文件处理完成之后,退出循环,通过platform_dt_match_best 将链表中的设备树进行多伦比较,将最终的设备树确定下来

	best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
			static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list){
				if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
					return NULL;
				if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
				return NULL;
				if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
				return NULL;
				if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
				return NULL;
				if (!update_dtb_entry_node(dt_list, DTB_SOC))
				return NULL;
				if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
				return NULL;
				if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
				......
				}
	if (best_match_dt_entry){
		bestmatch_tag = (void *)best_match_dt_entry->offset;
		bestmatch_tag_size = best_match_dt_entry->size;
		dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
			best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
			best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
			best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
			best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
			best_match_dt_entry->offset, best_match_dt_entry->size);
		dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
			best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
			best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
			board_pmic_target(0), board_pmic_target(1),
			board_pmic_target(2), board_pmic_target(3));
	}

最后打印出来的 即是在开机log中最常见的加载到的设备树的基本信息

[15880] [15880] Best match DTB tags 246/00000008/0x00000000/0/1000d/0/0/0/90a9c834/29307
[15890] [15890] Using pmic info 0x1000d/0x0/0x0/0x0 for device 0x1010d/0x0/0x0/0x0

4:实际修改

了解了以上流程之后,再来区别 如何select设备树就很简单了,下面给出一个实例。
在追溯代码的过程中,发现,这些id虽然可以自行修改,但是其中有些id在lk启动流程中会参加多次判断 比如, board-id 为8,意味着 platform=HW_PLATFORM_MTP, msm-id 为 245 意味着,平台是MSM8909,这些宏在启动过程中会参加一些逻辑的判断,比如panel_select 为了不涉及到更多地方的修改,这里选择修改board_hardware_subtype (即platform_subtype),根据gpio的状态,如果为高电平,就将此id修改为1. 在platform_detect()中添加:

	gpio_tlmm_config(TLMM_BOOT_SELECT_GPIO, 0, 0, 3, 0, 0);
	udelay(5000);
	board.platform_subtype = gpio_status(TLMM_BOOT_SELECT_GPIO);

根据上述最终在msm8909平台上最终生效的是 msm8909-1gb-mtp.dts(根据自己实际项目决定)配置来看,可以复制一份 msm8909-1gb-mtp.dts 为 msm8909-1gb-mtp-st.dts(makefile要添加好) 将其中的id修改为 qcom,board-id= <8 1> 然后将引用的“主”设备树文件msm8909-mtp.dtsi(这里的主是指最常修改的那个,最终都会合并成一个文件编译成dtb文件),复制并修改为msm8909-mtp-st.dtsi 这样当TLMM_BOOT_SELECT_GPIO(自行定义一个gpio) 为高时,使用的就是新建的设备树文件中的内容,反之还是原设备树文件生效。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐