高通平台LCD之MDP code解析

LCD相关code所在目录:
        kernel/drvier/video/msm/mdss/ 
软件驱动主要分为三部分:
        MDP 驱动
        DSI 控制器驱动
        FrameBuffer驱动
执行probe 的先后顺序:
       MDP probe →  DSI probe → FB probe

MDP probe:对使用的硬件资源进行初始化,同时在fb设备中注册mdp的使用接口
(rc = mdss_fb_register_mdp_instance(&mdp5);)
接口定义如下:
struct msm_mdp_interface mdp5 = {
.init_fnc = mdss_mdp_overlay_init,
.fb_mem_get_iommu_domain = mdss_fb_mem_get_iommu_domain,
.fb_stride = mdss_mdp_fb_stride,
.check_dsi_status = mdss_check_dsi_ctrl_status,
.get_format_params = mdss_mdp_get_format_params,
};

DSI probe:解析模组厂提供的panel的dtsi文件,从文件中获得panel的mode,分辨率,帧率,command数据等。

FB probe:从DSI的数据结构中获取到panel的相关信息,多MDP进行初始化。
 if (mfd->mdp.init_fnc) {
                rc= mfd->mdp.init_fnc(mfd);
                if(rc) {
                        pr_err("init_fncfailed\n");
                        returnrc;
                }
        }
init_fnc 就是 MDP probe 注册的  mdss_mdp_overlay_init。
在 mdss_mdp_overlay_init 中,首先是对mdp interface 注册回调函数。
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
struct msm_mdp_interface *mdp5_interface = &mfd->mdp;
struct mdss_overlay_private *mdp5_data = NULL;
struct irq_info *mdss_irq;
int rc;

mdp5_data = kzalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
if (!mdp5_data) {
pr_err("fail to allocate mdp5 private data structure");
return -ENOMEM;
}

mdp5_data->mdata = dev_get_drvdata(mfd->pdev->dev.parent);
if (!mdp5_data->mdata) {
pr_err("unable to initialize overlay for fb%d\n", mfd->index);
rc = -ENODEV;
goto init_fail;
}
//注册回调函数
mdp5_interface->on_fnc = mdss_mdp_overlay_on;
mdp5_interface->off_fnc = mdss_mdp_overlay_off;
mdp5_interface->release_fnc = __mdss_mdp_overlay_release_all;
mdp5_interface->do_histogram = NULL;
if (mdp5_data->mdata->ncursor_pipes)
mdp5_interface->cursor_update = mdss_mdp_hw_cursor_pipe_update;
else
mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
mdp5_interface->async_position_update =
mdss_mdp_async_position_update;
mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
mdp5_interface->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
mdp5_interface->mode_switch = mdss_mode_switch;
mdp5_interface->mode_switch_post = mdss_mode_switch_post;
mdp5_interface->pre_commit_fnc = mdss_mdp_overlay_precommit;
mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
mdp5_interface->splash_init_fnc = mdss_mdp_splash_init;
mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
mdp5_interface->input_event_handler = mdss_mdp_input_event_handler;

if (mfd->panel_info->type == WRITEBACK_PANEL) {
mdp5_interface->atomic_validate =
mdss_mdp_layer_atomic_validate_wfd;
mdp5_interface->pre_commit = mdss_mdp_layer_pre_commit_wfd;
mdp5_interface->is_config_same = mdss_mdp_wfd_is_config_same;
} else {
mdp5_interface->atomic_validate =
mdss_mdp_layer_atomic_validate;
mdp5_interface->pre_commit = mdss_mdp_layer_pre_commit;
}

INIT_LIST_HEAD(&mdp5_data->pipes_used);
INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
INIT_LIST_HEAD(&mdp5_data->pipes_destroy);
INIT_LIST_HEAD(&mdp5_data->bufs_pool);
INIT_LIST_HEAD(&mdp5_data->bufs_chunks);
INIT_LIST_HEAD(&mdp5_data->bufs_used);
INIT_LIST_HEAD(&mdp5_data->bufs_freelist);
INIT_LIST_HEAD(&mdp5_data->rot_proc_list);
mutex_init(&mdp5_data->list_lock);
mutex_init(&mdp5_data->ov_lock);
mutex_init(&mdp5_data->dfps_lock);
mdp5_data->hw_refresh = true;
mdp5_data->cursor_ndx[CURSOR_PIPE_LEFT] = MSMFB_NEW_REQUEST;
mdp5_data->cursor_ndx[CURSOR_PIPE_RIGHT] = MSMFB_NEW_REQUEST;

mfd->mdp.private1 = mdp5_data;
mfd->wait_for_kickoff = true;

rc = mdss_mdp_overlay_fb_parse_dt(mfd);
if (rc)
return rc;

/*
* disable BWC if primary panel is video mode on specific
* chipsets to workaround HW problem.
*/
if (mdss_has_quirk(mdp5_data->mdata, MDSS_QUIRK_BWCPANIC) &&
mfd->panel_info->type == MIPI_VIDEO_PANEL && (0 == mfd->index))
mdp5_data->mdata->has_bwc = false;

mfd->panel_orientation = mfd->panel_info->panel_orientation;

if ((mfd->panel_info->panel_orientation & MDP_FLIP_LR) &&
(mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY))
mdp5_data->mixer_swap = true;

rc = sysfs_create_group(&dev->kobj, &mdp_overlay_sysfs_group);
if (rc) {
pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
goto init_fail;
}

mdp5_data->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd,
"vsync_event");
if (!mdp5_data->vsync_event_sd) {
pr_err("vsync_event sysfs lookup failed\n");
rc = -ENODEV;
goto init_fail;
}

mdp5_data->lineptr_event_sd = sysfs_get_dirent(dev->kobj.sd,
"lineptr_event");
if (!mdp5_data->lineptr_event_sd) {
pr_err("lineptr_event sysfs lookup failed\n");
rc = -ENODEV;
goto init_fail;
}

mdp5_data->hist_event_sd = sysfs_get_dirent(dev->kobj.sd,
"hist_event");
if (!mdp5_data->hist_event_sd) {
pr_err("hist_event sysfs lookup failed\n");
rc = -ENODEV;
goto init_fail;
}

mdp5_data->bl_event_sd = sysfs_get_dirent(dev->kobj.sd,
"bl_event");
if (!mdp5_data->bl_event_sd) {
pr_err("bl_event sysfs lookup failed\n");
rc = -ENODEV;
goto init_fail;
}

mdp5_data->ad_event_sd = sysfs_get_dirent(dev->kobj.sd,
"ad_event");
if (!mdp5_data->ad_event_sd) {
pr_err("ad_event sysfs lookup failed\n");
rc = -ENODEV;
goto init_fail;
}

mdp5_data->ad_bl_event_sd = sysfs_get_dirent(dev->kobj.sd,
"ad_bl_event");
if (!mdp5_data->ad_bl_event_sd) {
pr_err("ad_bl_event sysfs lookup failed\n");
rc = -ENODEV;
goto init_fail;
}

rc = sysfs_create_link_nowarn(&dev->kobj,
&mdp5_data->mdata->pdev->dev.kobj, "mdp");
if (rc)
pr_warn("problem creating link to mdp sysfs\n");

rc = sysfs_create_link_nowarn(&dev->kobj,
&mfd->pdev->dev.kobj, "mdss_fb");
if (rc)
pr_warn("problem creating link to mdss_fb sysfs\n");

if (mfd->panel_info->type == MIPI_VIDEO_PANEL) {
rc = sysfs_create_group(&dev->kobj,
&dynamic_fps_fs_attrs_group);
if (rc) {
pr_err("Error dfps sysfs creation ret=%d\n", rc);
goto init_fail;
}
}

if (mfd->panel_info->mipi.dms_mode ||
mfd->panel_info->type == MIPI_CMD_PANEL) {
rc = __vsync_retire_setup(mfd);
if (IS_ERR_VALUE(rc)) {
pr_err("unable to create vsync timeline\n");
goto init_fail;
}
}
mfd->mdp_sync_pt_data.async_wait_fences = true;

pm_runtime_set_suspended(&mfd->pdev->dev);
pm_runtime_enable(&mfd->pdev->dev);

kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");

mdss_irq = mdss_intr_line();

/* Adding event timer only for primary panel */
if ((mfd->index == 0) && (mfd->panel_info->type != WRITEBACK_PANEL)) {
mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq, NULL,
(void *)mdp5_data);
if (!mdp5_data->cpu_pm_hdl)
pr_warn("%s: unable to add event timer\n", __func__);
}
//如果连续显示被打开,则会调用mdss_mdp_overlay_handoff函数,此时,mdp5_data->ctl 还没有被初始化,所以调用__mdss_mdp_overlay_ctl_init 函数,在这个函数中会执行mdss_mdp_ctl_init,在这函数里,会根据panel的type类型,注册不同的控制函数。
在这里我们看出start_fuc根据不同的type注册的函数不同,所以在probe 的时候,不同的DSI mode 在初始化时注册的函数也不同,
         当我们在显示过程中要对DSI mode 做切换的时候,需要从初始化的注册函数开始进行重新配置。
         在__mdss_mdp_overlay_ctl_init 函数中,还会对vsync_handler进行注册,以及Mixer 的malloc 内存分配等工作。
         在这之后还要初始化MDP 所需要的clk,以及必要的成员进行初始化。
         在对MDP 初始化完成之后,还要对lcd使用的背光进行注册。
if (mfd->panel_info->cont_splash_enabled) {
rc = mdss_mdp_overlay_handoff(mfd);
if (rc) {
/*
* Even though handoff failed, it is not fatal.
* MDP can continue, just that we would have a longer
* delay in transitioning from splash screen to boot
* animation
*/
pr_warn("Overlay handoff failed for fb%d. rc=%d\n",
mfd->index, rc);
rc = 0;
}
}
mdp5_data->dyn_pu_state = mfd->panel_info->partial_update_enabled;

if (mdss_mdp_pp_overlay_init(mfd))
pr_warn("Failed to initialize pp overlay data.\n");
return rc;
init_fail:
kfree(mdp5_data);
return rc;
}
高通平台LCD之MDP code解析_第1张图片





你可能感兴趣的:(LCD驱动)