MTK LK阶段 display框架

LK 阶段 display流程整理,包括LCD显示流程,以及背光控制流程

MTK平台,kernel中的display框架和LK类似,后面更新

LK阶段display流程
./lk/kernel/main.c:186:
kmain
	// do any super early platform initialization
	platform_early_init();
	thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	bootstrap2
		arch_init();
		fs_init();
		platform_init(); //./lk/platform/mt6735/platform.c:974
			/* framebuffer的大小
			透过读id找到现在插入的LCM,根据LCM的分辨率申请相应大小的frame buffer并确定frame buffer起始地址*/
			g_fb_size = mt_disp_get_vram_size();
			//framebuffer的起始地址
			g_fb_base = mblock_reserve_ext(&g_boot_arg->mblock_info, g_fb_size, 0x10000, 0x80000000, 0, "framebuffer");
			//mtk display系统初始化 ddp中各个模块和lcm配置初始化
			mt_disp_init((void *)g_fb_base);
				primary_display_init(NULL);
					/* 根据 lcm_name 名字从 lcm_driver_list 数组表当中寻找lcm驱动进行匹配。并将找到的lcm驱动赋值到plcm->drv中,
						那么返回的plcm变量则包含lcm_drv的访问地址,这样就能访问lcm驱动的接口了 */
					disp_lcm_handle *disp_lcm_probe(char *plcm_name, LCM_INTERFACE_ID lcm_id)
						/* 判断LCM_DRIVER链表中lcm驱动的数量,如果为1个就直接拿来用给设备,不需要调用compare_id函数,如果多个就需要匹配硬件id号了。 */
						lcm_drv->compare_id() 
						for (i=0; i<_lcm_count(); i++) {
							/*vendor / mediatek/proprietary/bootable/bootloader/lk/dev/lcm/mt65xx_lcm_list.c
							  我们一般需要把厂家提供的lcm_driver添加到lcm_driver_list数组,*/
							lcm_drv= lcm_driver_list[i]; 
							DISPDBG("we will check lcm: %s\n", lcm_drv->name);
					/* 同kernel流程一样 */
					lcm_param = disp_lcm_get_params(pgc->plcm);
					if (primary_display_mode == DIRECT_LINK_MODE) {
						_build_path_direct_link();
							pgc->dpmgr_handle = dpmgr_create_path(DDP_SCENARIO_PRIMARY_DISP, pgc->cmdq_handle_config);
							
							//根据lcm接口类型获得目标模块,这里为DISP_MODULE_DSI0
							dst_module = _get_dst_module_by_lcm(pgc->plcm);
							
							//设置ddp的最后一个模块为DISP_MODULE_DSI0
							dpmgr_path_set_dst_module(pgc->dpmgr_handle, dst_module);
							dpmgr_set_lcm_utils(pgc->dpmgr_handle, pgc->plcm->drv);
								mod_drv->set_lcm_utils(module_name, lcm_drv);
									//设置各个模块中lcm相关的操作函数,调用ddp_dsi_set_lcm_utils,最终调用lcm_drv->set_util_funcs(utils)将操作函数赋给lcm_util
									ddp_dsi_set_lcm_utils 
										
						DISPCHECK("primary display is DIRECT LINK MODE\n");
					} else if (primary_display_mode == DECOUPLE_MODE) {
						_build_path_decouple(); 
						DISPCHECK("primary display is DECOUPLE MODE\n");
					} else if (primary_display_mode == SINGLE_LAYER_MODE) {
						_build_path_single_layer();
						DISPCHECK("primary display is SINGLE LAYER MODE\n");
					} else if (primary_display_mode == DEBUG_RDMA1_DSI0_MODE) {
						_build_path_debug_rdma1_dsi0();
					_build_cmdq_trigger_loop();
					_start_cmdq_trigger_loop();
					
					//ddp设置显示模式,video mode or command mode
					dpmgr_path_set_video_mode(pgc->dpmgr_handle, primary_display_is_video_mode());
					
					//ddp上各个模块的初始化,ovl0、ovl1、rdma0、rdma1、color、aal、gamma、dither、dsi0
					dpmgr_path_init(pgc->dpmgr_handle, CMDQ_DISABLE);
						ddp_modules_driver[module_name]->init(module_name, cmdqHandle); //ddp_info.c中对ddp_modules_driver赋值
					
					//data_config结构体描述lcm分辨率、接口类型、数据排列等信息
					disp_ddp_path_config data_config;
					memset((void*)&data_config, 0, sizeof(disp_ddp_path_config));
					memcpy(&(data_config.dsi_config), &(lcm_param->dsi), sizeof(LCM_DSI_PARAMS)); //这里只考虑DSI接口
					
					/* 长宽高,BPP初始化 */
					data_config.dst_w = disp_lcm_width(pgc->plcm);
					data_config.dst_h = disp_lcm_height(pgc->plcm);
					
					//调用各个模块的config函数
					ret = dpmgr_path_config(pgc->dpmgr_handle, &data_config, CMDQ_DISABLE);
						ddp_modules_driver[module_name]->config(module_name, config, cmdqHandle);
					
					//lcm初始化,通过回读0x0A寄存器判断lcm是否连接
					//依次调用lcm的init_power和init函数,实现上电复位初始化的动作,并通过回读0x0A寄存器判断跟lcm之前是否连接OK
					ret = disp_lcm_init(pgc->plcm);
						DISPFUNC();
						lcm_drv->init_power(); //调用LCM lcm init_power接口上电
						lcm_drv->init(); //调用LCM驱动lcm_init接口
						DISPCHECK("lcm init \n");
						ret = DSI_dcs_read_lcm_reg_v2(_get_dst_module_by_lcm(plcm), NULL, 0x0A, (UINT8 *)&buffer,1);
						DISPMSG("read from lcm 0x0A: %d\n", buffer);
						isLCMConnected = 1;
						DISPMSG("lcm is connected\n"); //LCM 驱动已经connect

					//关联event与irq,并且使能event,例如一帧刷完这个event,便产生一个中断
					//映射event和中断,并且使能中断事件
					dpmgr_map_event_to_irq(pgc->dpmgr_handle, DISP_PATH_EVENT_IF_VSYNC, DDP_IRQ_DSI0_FRAME_DONE);
					dpmgr_enable_event(pgc->dpmgr_handle, DISP_PATH_EVENT_IF_VSYNC);
					dpmgr_enable_event(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE);
				memset((void*)lcdbase, 0x0, DISP_GetVRamSize());
				
				//lk阶段定义了2层layer(最多支持4层layer),FB_LAYER和BOOT_MENU_LAYER, 
				primary_display_config_input(&input);
					//将各层layer信息传递给overlay
					ret = _convert_disp_input_to_ovl(&(data_config.ovl_config[input->layer]), input);
					
					//打开overlay模块配置,执行config函数(config函数会对ovl_dirty进行check,为0则直接返回,相当于bypass)
					data_config.ovl_dirty = 1;
					ret = dpmgr_path_config(pgc->dpmgr_handle, &data_config, primary_display_use_cmdq);
					
					// 设置显示需要触发overlay
					pgc->need_trigger_overlay = 1;
			drv_video_init();
			
			boot_mode_select(); //模式选择,例如fastboot,recoverary
			/* 将logo加载到分配的RAM中 */
			logo_size = mboot_common_load_logo((unsigned long)mt_get_logo_db_addr_pa(), "logo");
				mt_get_logo_db_addr_pa //返回logo的地址
					dprintf(0,"mt_get_logo_db_addr_pa: 0x%08x\n",(unsigned int)logo_db_addr_pa);
			PROFILING_START("show logo");
			
			//根据启动方式选择加载的logo,填充到fb中
			mt_disp_show_boot_logo(); 
				dprintf(INFO, "[lk logo: %s %d]\n",__FUNCTION__,__LINE__);
				mt_logo_get_custom_if();
					init_fb_screen();
					fill_animation_logo(BOOT_LOGO_INDEX, mt_get_fb_buf(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen);
					mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
			PROFILING_START("backlight");
			
			刷新fb有关的cache,并且调用各个模块start和trigger函数将fb内容更新到lcm上
			mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
		apps_init();


APP_START(mt_boot)
.init = mt_boot_init,
 APP_END


mt_boot_init
	set_serial_num();
	boot_linux_from_storage(); //vendor/mediatek/proprietary/bootable/bootloader/lkapp/mt_boot/mt_boot.c
		bootargs_init((void *)tags_target_addr);
		custom_port_in_kernel(g_boot_mode, cmdline_get());
		send_root_of_trust_info();
		set_boot_phase(BOOT_PHASE_KERNEL);
		boot_linux((void *)kernel_target_addr, (unsigned *)tags_target_addr, board_machtype(), (void *)ramdisk_target_addr, ramdisk_real_sz);
			boot_linux_fdt((void *)kernel, (unsigned *)tags, machtype, (void *)ramdisk, ramdisk_sz);
				load_images(g_boot_mode);
				mt_disp_config_frame_buffer(fdt);
				target_fdt_firmware(fdt, sn_buf);
					res = mt_disp_get_lcd_product_codes(lcd_product_codes);
						res = primary_display_get_lcd_product_codes(out);
							res = disp_lcm_get_product_codes(pgc->plcm, out);
								lcm_drv->get_lcd_product_codes(out);
		

	fastboot:
		target_fastboot_init();
		mt_part_dump();
		sz = target_get_max_flash_size();
		fastboot_init(target_get_scratch_address(), sz);
		udc_start();


		
/* LK将lcm相关的信息,写到cmdline中,传递给kernel */
void cmd_boot(const char *arg, void *data, unsigned sz)	
	n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "lcm=%1d-%s", DISP_IsLcmFound(), mt_disp_get_lcm_id());
	cmdline_append(cmdline_tmpbuf);
	n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "fps=%1d", mt_disp_get_lcd_time());
	cmdline_append(cmdline_tmpbuf);
	n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "vram=%1d", DISP_GetVRamSize());
	cmdline_append(cmdline_tmpbuf);	

 
/* kernel中从 "/chosen" 获取 LCM 信息 */
mtkfb_find_lcm_driver
	_parse_tag_videolfb();
		chosen_node = of_find_node_by_path("/chosen");
		__parse_tag_videolfb(chosen_node);
			videolfb_tag = (struct tag_video_lfb *)of_get_property(node, "atag,videolfb", (int *)&size);
			memset((void *)mtkfb_lcm_name, 0, sizeof(mtkfb_lcm_name));
			strncpy((char *)mtkfb_lcm_name, videolfb_tag->lcmname, sizeof(mtkfb_lcm_name));
			lcd_fps = videolfb_tag->fps;
			vramsize = videolfb_tag->vram;
			fb_base = videolfb_tag->fb_base;
	return mtkfb_lcm_name;

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个专注于USB的驱动工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值