MTK LCM流程
LCM的设备模型是遵守设备总线驱动结构的
总线
platform虚拟总线,在该总线的设备和驱动通过name来匹配。
设备
设备定义在设备树 在/kernel-3.18/arch/arm/boot/dts/mt6735m.dtsi 或 bd6735m_35g_b_m0.dts
驱动
驱动文件出了MTK抽象出来的具体设备驱动文件外,这里指的是挂在platform上的驱动文件。kernel-3.18/drivers/misc/mediatek/video/common/mtkfb.c。
static const struct of_device_id mtkfb_of_ids[] = {
{.compatible = "mediatek,mtkfb",},
{}
};
const struct dev_pm_ops mtkfb_pm_ops = {
.suspend = mtkfb_pm_suspend,
.resume = mtkfb_pm_resume,
.freeze = mtkfb_pm_freeze,
.thaw = mtkfb_pm_resume,
.poweroff = mtkfb_pm_suspend,
.restore = mtkfb_pm_resume,
.restore_noirq = mtkfb_pm_restore_noirq,
};
static struct platform_driver mtkfb_driver = {
.driver = {
.name = MTKFB_DRIVER,
#ifdef CONFIG_PM
.pm = &mtkfb_pm_ops,
#endif
.bus = &platform_bus_type,
.probe = mtkfb_probe,
.remove = mtkfb_remove,
.suspend = mtkfb_suspend,
.resume = mtkfb_resume,
.shutdown = mtkfb_shutdown,
.of_match_table = mtkfb_of_ids,
},
};
注册驱动
int __init mtkfb_init(void)
{
int r = 0;
MSG_FUNC_ENTER();
if (platform_driver_register(&mtkfb_driver)) {
PRNERR("failed to register mtkfb driver\n");
r = -ENODEV;
goto exit;
}
#if 0
#ifdef CONFIG_HAS_EARLYSUSPEND
register_early_suspend(&mtkfb_early_suspend_handler);
#endif
#endif
/* FIXME: find definition */
PanelMaster_Init();
DBG_Init();
mtkfb_ipo_init();
exit:
MSG_FUNC_LEAVE();
return r;
}
驱动的名字和设备匹配后,调用驱动的probe进行探测设备,
mtkfb_probe()有
/*mtkfb should parse lcm name from kernel boot command line */
primary_display_init(mtkfb_find_lcm_driver(),lcd_fps); //加载定制化的驱动,其中mtkfb_find_lcm_driver()查找到对应驱动
char *mtkfb_find_lcm_driver(void)
{
#ifdef CONFIG_OF
if( 1 == _parse_tag_videolfb()){
}
#else
#endif
return mtkfb_lcm_name;
}
再来看
int _parse_tag_videolfb(void)
{
struct tag_videolfb *videolfb_tag = NULL;
/* not necessary */
/* DISPCHECK("[DT][videolfb]isvideofb_parse_done = %d\n",is_videofb_parse_done); */
if (is_videofb_parse_done)
return 0;
#ifdef MTK_NO_DISP_IN_LK
DISPCHECK("[DT][videolfb] zaikuo, workaround for LK not ready\n"); /* after LK ready, remove this code */
return 1;
#endif
if (of_scan_flat_dt(fb_early_init_dt_get_chosen, NULL) > 0) {
videolfb_tag = (struct tag_videolfb *)of_get_flat_dt_prop(video_node, "atag,videolfb", NULL);
if (videolfb_tag) {
memset((void *)mtkfb_lcm_name, 0, sizeof(mtkfb_lcm_name));
strcpy((char *)mtkfb_lcm_name, videolfb_tag->lcmname);
mtkfb_lcm_name[strlen(videolfb_tag->lcmname)] = '\0';
lcd_fps = videolfb_tag->fps;
if (0 == lcd_fps)
lcd_fps = 6000;
islcmconnected = videolfb_tag->islcmfound;
vramsize = videolfb_tag->vram;
fb_base = videolfb_tag->fb_base;
is_videofb_parse_done = 1;
DISPPRINT("[DT][videolfb] lcmfound=%d, fps=%d, fb_base=%p, vram=%d, lcmname=%s\n",
islcmconnected, lcd_fps, (void *)fb_base, vramsize, mtkfb_lcm_name);
#if 0
DISPCHECK("[DT][videolfb] islcmfound = %d\n", islcmconnected);
DISPCHECK("[DT][videolfb] fps = %d\n", lcd_fps);
DISPCHECK("[DT][videolfb] fb_base = %p\n", (void *)fb_base);
DISPCHECK("[DT][videolfb] vram = %d\n", vramsize);
DISPCHECK("[DT][videolfb] lcmname = %s\n", mtkfb_lcm_name);
#endif
return 0;
}
DISPCHECK("[DT][videolfb] videolfb_tag not found\n");
return 1;
}
DISPCHECK("[DT][videolfb] of_chosen not found\n");
return 1;
}
从运行log中可以看到lcmname=jd9522_hd720_dsi_vdo_qc
[ 0.477467] <0>.(0)[1:swapper/0][name:mtkfb&][DISP][DT][videolfb] lcmfound=1, fps=5764, fb_base=7f330000, vram=13172736, lcmname=jd9522_hd720_dsi_vdo_qc
回过来看
primary_display_init() //kernel-3.18/drivers/misc/mediatek/video/mt6757/videox/primary_display.c
进入primary_display_init函数中,再执行disp_lcm_probe()函数。
pgc->plcm=disp_lcm_probe(lcm_name,LCM_INTERFACE_NOTDEFFINE)
kernel-3.18/drivers/misc/mediatek/video/mt6757/videox/disp_lcm.c中
disp_lcm_probe()找到驱动jd9522_hd720_dsi_vdo_qc,并返回一个disp_lcm_handle指针,获得lcm参数。
下面是对LK代码中LCM驱动的选择流程分析
LK核心流程
kmain()依次执行
thread_init_early()
arch_early_init()
platform_early_init()
call_constructors()
bootstrap2()
然后Bootstrap2依次执行
platform_init()
app_init()
mt_boot_init()
boot_linux_from_storage()
boot_linux()
在platform_init()中
mt_disp_init((void *)g_fb_base);
在mt_disp_init()中调用
primay_display_init(NULL) // 类似kernel中操作,只是这个地方传入为NULL, 而kernel中传入的是lk传递过去lcm_name;
在primay_display_init()中也是执行,支持lcm_name为null。
pgc->plcm = disp_lcm_probe( lcm_name, LCM_INTERFACE_NOTDEFINED);
??
通过调用文件Mt_boot.c (app\mt_boot)中的int boot_linux_from_storage(void)函数中
ret = fdt_setprop(fdt, offset, "atag,videolfb", buf, ptr - buf);
传递给kernel