3 高通LCD上下电过程简析

上下电代码位于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\n",
			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\n", 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\n");
		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\n", 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\n");
		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\n", __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\n");
	if (pdata == NULL) {
		pr_err("%s: Invalid input data\n", __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\n",
			__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\n");
		ret = mdss_dsi_panel_reset(pdata, 1);
		if (ret)
			pr_err("%s: Panel reset failed. rc=%d\n",
					__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\n",
							__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);
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值