3 高通LCD上下电过程简析

2019-04-13 12:34发布

上下电代码位于mdss_fb.c中。在mdss_fb_register()函数中会设置fb用户空间操作函数: fbi->fbops = &mdss_fb_ops; static struct fb_ops mdss_fb_ops = { .owner = THIS_MODULE, .fb_open = mdss_fb_open, .fb_release = mdss_fb_release, .fb_check_var = mdss_fb_check_var, /* vinfo check */ .fb_set_par = mdss_fb_set_par, /* set the video mode */ .fb_blank = mdss_fb_blank, /* blank display */ .fb_pan_display = mdss_fb_pan_display, /* pan display */ .fb_ioctl_v2 = mdss_fb_ioctl, /* perform fb specific ioctl */ #ifdef CONFIG_COMPAT .fb_compat_ioctl_v2 = mdss_fb_compat_ioctl, #endif .fb_mmap = mdss_fb_mmap, }; 用户空间通过mdss_fb_blank()函数来设置屏的亮灭。 static int mdss_fb_blank(int blank_mode, struct fb_info *info) { int ret; struct mdss_panel_data *pdata; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; ret = mdss_fb_pan_idle(mfd); if (ret) { pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d ", mfd->index, ret); return ret; } // 注册成功后,op_enable = true if (mfd->op_enable == 0) { if (blank_mode == FB_BLANK_UNBLANK) mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON; else if (blank_mode == BLANK_FLAG_ULP) mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP2; else if (blank_mode == BLANK_FLAG_LP) mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1; else mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF; return 0; } pr_debug("mode: %d ", blank_mode); pdata = dev_get_platdata(&mfd->pdev->dev); if (pdata->panel_info.is_lpm_mode && blank_mode == FB_BLANK_UNBLANK) { pr_debug("panel is in lpm mode "); mfd->mdp.configure_panel(mfd, 0, 1); mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type); pdata->panel_info.is_lpm_mode = false; } return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); } 最后调用函数mdss_fb_blank_sub()实现。 static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, int op_enable) blank_mode这个参数的值主要有两个,FB_BLANK_UNBLANK和 FB_BLANK_POWERDOWN:
  • FB_BLANK_UNBLANK 是亮屏操作;
  • FB_BLANK_POWERDOWN 是灭屏操作;
当亮屏时,传入参数FB_BLANK_UNBLANK,函数调用过程: static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, int op_enable) { switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("unblank called. cur pwr state=%d ", cur_power_state); ret = mdss_fb_blank_unblank(mfd); break; case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: default: req_power_state = MDSS_PANEL_POWER_OFF; pr_debug("blank powerdown called "); ret = mdss_fb_blank_blank(mfd, req_power_state); break; } } 查看mdss_fb_blank_unblank()的实现: static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd) { /* Start Display thread 开一个线程处理什么,不懂 */ if (mfd->disp_thread == NULL) { ret = mdss_fb_start_disp_thread(mfd); if (IS_ERR_VALUE(ret)) return ret; } if (mfd->mdp.on_fnc) { struct mdss_panel_info *panel_info = mfd->panel_info; struct fb_var_screeninfo *var = &mfd->fbi->var; /* 调用mdp.on_fnc回调函数 */ ret = mfd->mdp.on_fnc(mfd); if (ret) { mdss_fb_stop_disp_thread(mfd); goto error; } mfd->panel_power_state = MDSS_PANEL_POWER_ON; mfd->panel_info->panel_dead = false; mutex_lock(&mfd->update.lock); mfd->update.type = NOTIFY_TYPE_UPDATE; mfd->update.is_suspend = 0; mutex_unlock(&mfd->update.lock); /* * Panel info can change depending in the information * programmed in the controller. * Update this info in the upstream structs. */ mdss_panelinfo_to_fb_var(panel_info, var); /* Start the work thread to signal idle time */ if (mfd->idle_time) schedule_delayed_work(&mfd->idle_notify_work, msecs_to_jiffies(mfd->idle_time)); } } 亮屏过程,将调用mfd->mdp.on_fnc()回调函数,这个回调在mdp3_ctrl_init()函数中指定为mdp3_ctrl_on()。 @mdp3_ctrl.c static int mdp3_ctrl_on(struct msm_fb_data_type *mfd) { int rc = 0; struct mdp3_session_data *mdp3_session; struct mdss_panel_data *panel; if (panel->event_handler) { rc = panel->event_handler(panel, MDSS_EVENT_LINK_READY, NULL); rc |= panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL); rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL); if (panel->panel_info.type == MIPI_CMD_PANEL) { struct dsi_panel_clk_ctrl clk_ctrl; clk_ctrl.state = MDSS_DSI_CLK_ON; clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT; rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_CLK_CTRL, (void *)&clk_ctrl); } } } 在mdp3_ctrl_on()中,调用panel->event_handler来处理亮屏的各个事件,包括: 1、MDSS_EVENT_LINK_READY 2、MDSS_EVENT_UNBLANK 3、MDSS_EVENT_PANEL_ON 4、MDSS_EVENT_PANEL_CLK_CTRL 接下来看panel->event_handler对这些事件的处理过程。 panel->event_handler在mdss_dsi.c中指向mdss_dsi_event_handler()函数。 首先处理MDSS_EVENT_LINK_READY事件: static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; switch (event) { case MDSS_EVENT_CHECK_PARAMS: pr_debug("%s:Entered Case MDSS_EVENT_CHECK_PARAMS ", __func__); if (mdss_dsi_check_params(ctrl_pdata, arg)) { ctrl_pdata->update_phy_timing = true; /* * Call to MDSS_EVENT_CHECK_PARAMS expects * the return value of 1, if there is a change * in panel timing parameters. */ rc = 1; } ctrl_pdata->refresh_clk_rate = true; break; case MDSS_EVENT_LINK_READY: if (ctrl_pdata->refresh_clk_rate) rc = mdss_dsi_clk_refresh(pdata, ctrl_pdata->update_phy_timing); mdss_dsi_get_hw_revision(ctrl_pdata); mdss_dsi_get_phy_revision(ctrl_pdata); rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); break; case MDSS_EVENT_UNBLANK: if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_POST_PANEL_ON: rc = mdss_dsi_post_panel_on(pdata); break; case MDSS_EVENT_PANEL_ON: ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_unblank(pdata); pdata->panel_info.esd_rdy = true; break; } } 在处理ready事件时,主要调用 mdss_dsi_on(pdata)函数。 int mdss_dsi_on(struct mdss_panel_data *pdata) ret = mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON); mdss_dsi_panel_power_on(pdata); static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata) { int ret = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; printk("~~~mdss_dsi_panel_power_on "); if (pdata == NULL) { pr_err("%s: Invalid input data ", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); ret = msm_dss_enable_vreg( ctrl_pdata->panel_power_data.vreg_config, ctrl_pdata->panel_power_data.num_vreg, 1); if (ret) { pr_err("%s: failed to enable vregs for %s ", __func__, __mdss_dsi_pm_name(DSI_PANEL_PM)); return ret; } /* * If continuous splash screen feature is enabled, then we need to * request all the GPIOs that have already been configured in the * bootloader. This needs to be done irresepective of whether * the lp11_init flag is set or not. */ if (pdata->panel_info.cont_splash_enabled || !pdata->panel_info.mipi.lp11_init) { if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true)) pr_debug("reset enable: pinctrl not enabled "); ret = mdss_dsi_panel_reset(pdata, 1); if (ret) pr_err("%s: Panel reset failed. rc=%d ", __func__, ret); } return ret; } 在处理MDSS_EVENT_UNBLANK事件时,主要调用mdss_dsi_unblank()函数。 @mdss_dsi.c static int mdss_dsi_unblank(struct mdss_panel_data *pdata) { int ret = 0; struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) { if (!pdata->panel_info.dynamic_switch_pending) { ATRACE_BEGIN("dsi_panel_on"); // 调用ctrl_pdata->on()回调函数 ret = ctrl_pdata->on(pdata); if (ret) { pr_err("%s: unable to initialize the panel ", __func__); goto error; } ATRACE_END("dsi_panel_on"); } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; } } ctrl_pdata->on指针指向mdss_dsi_panel_on()函数,在mdss_dsi_panel.c::mdss_dsi_panel_init()中定义: static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl = NULL; struct mdss_panel_info *pinfo; struct dsi_panel_cmds *on_cmds; pinfo = &pdata->panel_info; ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); on_cmds = &ctrl->on_cmds; // 发送上电指令 if (on_cmds->cmd_cnt) mdss_dsi_panel_cmds_send(ctrl, on_cmds, CMD_REQ_COMMIT); }