static u32 mdss_mdp_res_init(struct platform_device *pdev)
{
	u32 rc;

	rc = mdss_mdp_irq_clk_setup(pdev);
	if (rc)
		return rc;

	mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
	INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
			  mdss_mdp_clk_ctrl_workqueue_handler);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
	mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
	mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
	mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
	mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;

	pr_info("mdss_revision=%x\n", mdss_res->rev);
	pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);

	mdss_res->res_init = true;
	mdss_res->timeout = HZ/20;
	mdss_res->clk_ena = false;
	mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
	mdss_res->suspend = false;
	mdss_res->prim_ptype = NO_PANEL;
	mdss_res->irq_ena = false;

	return 0;
}
예제 #2
0
int mdss_dsi_panel_ief_on(void)
{
	struct mdss_dsi_ctrl_pdata *ctrl = NULL;

	if (pdata_base == NULL || mfd_base == NULL) {
		pr_err("%s: Invalid input data\n", __func__);
		return -EINVAL;
	}

	if (mfd_base->panel_power_on == 0) {
		pr_err("%s: Panel is off\n", __func__);
		return -EPERM;
	}

	ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata,	panel_data);

	if(lge_ief_on_cmds.cmd_cnt){
		pr_info("sending IEF_ON code\n");
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
		mdss_dsi_panel_cmds_send(ctrl, &lge_ief_on_cmds);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	}

	return 0;
}
예제 #3
0
static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
{
	u32 rc = 0;

	rc = mdss_mdp_irq_clk_setup(mdata);
	if (rc)
		return rc;

	mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
	INIT_DELAYED_WORK(&mdata->clk_ctrl_worker,
			  mdss_mdp_clk_ctrl_workqueue_handler);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	mdata->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
	mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
	mdata->pipe_type_map = mdss_mdp_pipe_type_map;
	mdata->mixer_type_map = mdss_mdp_mixer_type_map;

	pr_info("mdss_revision=%x\n", mdata->rev);
	pr_info("mdp_hw_revision=%x\n", mdata->mdp_rev);

	mdata->res_init = true;
	mdata->timeout = HZ/20;
	mdata->clk_ena = false;
	mdata->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
	mdata->suspend = false;
	mdata->prim_ptype = NO_PANEL;
	mdata->irq_ena = false;

	mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
	if (IS_ERR_OR_NULL(mdata->iclient)) {
		pr_err("msm_ion_client_create() return error (%p)\n",
				mdata->iclient);
		mdata->iclient = NULL;
	}

	rc = mdss_iommu_init();
	if (!IS_ERR_VALUE(rc))
		mdss_iommu_attach();

	rc = mdss_hw_init(mdata);

	return rc;
}
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
{
	struct mdss_mdp_video_ctx *ctx;
	u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC;

	pr_debug("kickoff ctl=%d\n", ctl->num);

	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
	if (!ctx) {
		pr_err("invalid ctx\n");
		return -ENODEV;
	}
	mdss_mdp_set_intr_callback(intr_type, ctl->intf_num,
				   mdss_mdp_video_vsync_intr_done, ctx);
	mdss_mdp_irq_enable(intr_type, ctl->intf_num);

	if (!ctx->timegen_en) {
		int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);

		pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);

		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
		ctx->timegen_en = true;
		wmb();
	}

	wait_for_completion_interruptible(&ctx->vsync_comp);
	mdss_mdp_irq_disable(intr_type, ctl->intf_num);

	return 0;
}
예제 #5
0
int mdss_edp_off(struct mdss_panel_data *pdata)
{
	struct mdss_edp_drv_pdata *edp_drv = NULL;
	int ret = 0;

	edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
				panel_data);
	if (!edp_drv) {
		pr_err("%s: Invalid input data\n", __func__);
		return -EINVAL;
	}
	pr_debug("%s:+\n", __func__);

	mdss_edp_irq_disable(edp_drv);

	gpio_set_value(edp_drv->gpio_panel_en, 0);
	if (edp_drv->bl_pwm != NULL)
		pwm_disable(edp_drv->bl_pwm);
	mdss_edp_enable(edp_drv->base, 0);
	mdss_edp_unconfig_clk(edp_drv->base, edp_drv->mmss_cc_base);
	mdss_edp_enable_mainlink(edp_drv->base, 0);

	mdss_edp_lane_power_ctrl(edp_drv->base,
				edp_drv->dpcd.max_lane_count, 0);
	mdss_edp_clk_disable(edp_drv);
	mdss_edp_phy_powerup(edp_drv->base, 0);
	mdss_edp_unprepare_clocks(edp_drv);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	mdss_edp_aux_ctrl(edp_drv->base, 0);

	pr_debug("%s:-\n", __func__);
	return ret;
}
static int prepare_for_reg_access(struct msm_fb_data_type *mfd)
{
	struct mdss_panel_data *pdata;
	int ret = 0;
	struct mdss_mdp_ctl *ctl;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;

	ctl = mfd_to_ctl(mfd);
	if (!ctl)
		return -ENODEV;

	pdata = dev_get_platdata(&mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: no panel connected\n", __func__);
		return -ENODEV;
	}

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
				panel_data);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	mdss_dsi_cmd_mdp_busy(ctrl_pdata);
	mdss_bus_bandwidth_ctrl(1);
	mdss_dsi_clk_ctrl(ctrl_pdata, 1);

	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);

	return ret;
}
static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
{
	struct mdss_mdp_mixer *mixer;
	u32 cnt = 0xffff;	/* init it to an invalid value */
	u32 init;
	u32 height;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);

	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
	if (!mixer) {
		mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
		if (!mixer) {
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
			goto exit;
		}
	}

	init = mdss_mdp_pingpong_read
		(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL) & 0xffff;

	height = mdss_mdp_pingpong_read
		(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT) & 0xffff;

	if (height < init) {
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
		goto exit;
	}

	cnt = mdss_mdp_pingpong_read
		(mixer, MDSS_MDP_REG_PP_INT_COUNT_VAL) & 0xffff;

	if (cnt < init)		/* wrap around happened at height */
		cnt += (height - init);
	else
		cnt -= init;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	pr_debug("cnt=%d init=%d height=%d\n", cnt, init, height);
exit:
	return cnt;
}
예제 #8
0
int mdss_hw_init(struct mdss_data_type *mdata)
{
	int i, j;
	char *offset;
	struct mdss_mdp_pipe *vig;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
	pr_info_once("MDP Rev=%x\n", mdata->mdp_rev);

	if (mdata->hw_settings) {
		struct mdss_hw_settings *hws = mdata->hw_settings;

		while (hws->reg) {
			writel_relaxed(hws->val, hws->reg);
			hws++;
		}
	}

	for (i = 0; i < mdata->nmixers_intf; i++) {
		offset = mdata->mixer_intf[i].dspp_base +
				MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
		for (j = 0; j < ENHIST_LUT_ENTRIES; j++)
			writel_relaxed(j, offset);

		/* swap */
		writel_relaxed(1, offset + 4);
	}
	vig = mdata->vig_pipes;
	for (i = 0; i < mdata->nvig_pipes; i++) {
		offset = vig[i].base +
			MDSS_MDP_REG_VIG_HIST_LUT_BASE;
		for (j = 0; j < ENHIST_LUT_ENTRIES; j++)
			writel_relaxed(j, offset);
		/* swap */
		writel_relaxed(1, offset + 16);
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	pr_debug("MDP hw init done\n");

	return 0;
}
예제 #9
0
int mdss_edp_on(struct mdss_panel_data *pdata)
{
	struct mdss_edp_drv_pdata *edp_drv = NULL;
	int ret = 0;

	if (!pdata) {
		pr_err("%s: Invalid input data\n", __func__);
		return -EINVAL;
	}

	edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
			panel_data);

	pr_debug("%s:+\n", __func__);
	if (edp_drv->train_start == 0)
		edp_drv->train_start++;

	mdss_edp_phy_pll_reset(edp_drv->base);
	mdss_edp_aux_reset(edp_drv->base);
	mdss_edp_mainlink_reset(edp_drv->base);

	ret = mdss_edp_prepare_clocks(edp_drv);
	if (ret)
		return ret;
	mdss_edp_phy_powerup(edp_drv->base, 1);

	mdss_edp_pll_configure(edp_drv->base, edp_drv->edid.timing[0].pclk);
	mdss_edp_phy_pll_ready(edp_drv->base);

	ret = mdss_edp_clk_enable(edp_drv);
	if (ret) {
		mdss_edp_unprepare_clocks(edp_drv);
		return ret;
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);

	mdss_edp_aux_ctrl(edp_drv->base, 1);

	mdss_edp_lane_power_ctrl(edp_drv->base,
				edp_drv->dpcd.max_lane_count, 1);
	mdss_edp_enable_mainlink(edp_drv->base, 1);
	mdss_edp_config_clk(edp_drv->base, edp_drv->mmss_cc_base);

	mdss_edp_clock_synchrous(edp_drv->base, 1);
	mdss_edp_phy_vm_pe_init(edp_drv->base);
	mdss_edp_config_sync(edp_drv->base);
	mdss_edp_config_sw_div(edp_drv->base);
	mdss_edp_config_static_mdiv(edp_drv->base);
	gpio_set_value(edp_drv->gpio_panel_en, 1);
	mdss_edp_irq_enable(edp_drv);

	pr_debug("%s:-\n", __func__);
	return 0;
}
예제 #10
0
static int mdss_hw_init(struct mdss_data_type *mdata)
{
	char *base = mdata->vbif_base;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	/* Setup VBIF QoS settings*/
	MDSS_MDP_REG_WRITE(0x2E0, 0x000000AA);
	MDSS_MDP_REG_WRITE(0x2E4, 0x00000055);
	writel_relaxed(0x00000001, base + 0x004);
	writel_relaxed(0x00000707, base + 0x0D8);
	writel_relaxed(0x00000030, base + 0x0F0);
	writel_relaxed(0x00000001, base + 0x124);
	writel_relaxed(0x00000FFF, base + 0x178);
	writel_relaxed(0x0FFF0FFF, base + 0x17C);
	writel_relaxed(0x22222222, base + 0x160);
	writel_relaxed(0x00002222, base + 0x164);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	pr_debug("MDP hw init done\n");

	return 0;
}
예제 #11
0
static void mdss_mdp_pipe_nrt_vbif_setup(struct mdss_data_type *mdata,
					struct mdss_mdp_pipe *pipe)
{
	uint32_t nrt_vbif_client_sel;

	if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
		return;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	nrt_vbif_client_sel = readl_relaxed(mdata->mdp_base +
				MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL);
	if (mdss_mdp_is_nrt_vbif_client(mdata, pipe))
		nrt_vbif_client_sel |= BIT(pipe->num - MDSS_MDP_SSPP_DMA0);
	else
		nrt_vbif_client_sel &= ~BIT(pipe->num - MDSS_MDP_SSPP_DMA0);
	writel_relaxed(nrt_vbif_client_sel,
			mdata->mdp_base + MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	return;
}
예제 #12
0
static void mdss_mdp_suspend_sub(void)
{
	cancel_delayed_work(&mdss_res->clk_ctrl_worker);

	flush_workqueue(mdss_res->clk_ctrl_wq);

	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);

	mutex_lock(&mdp_suspend_mutex);
	mdss_res->suspend = true;
	mutex_unlock(&mdp_suspend_mutex);
}
예제 #13
0
int mdss_dsi_panel_img_tune_apply(unsigned int screen_mode)
{
	struct mdss_dsi_ctrl_pdata *ctrl = NULL;

	if (pdata_base == NULL) {
		pr_err("%s: Invalid input data.\n", __func__);
		return -EINVAL;
	}
	ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata,
				panel_data);
	if (pdata_base->panel_info.panel_power_on == 0) {
		pr_err("%s: panel off state. This screen mode will not be applied.\n", __func__);
		return -EINVAL;
	}
	/*
		if (ctrl->ctrl_state != (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE)) {
			pr_err("%s: panel is not 'on' state(cur=%d). The screen mode will be applied next time.\n", __func__, ctrl->ctrl_state);
			return -EINVAL;
		}
	*/
	if ((screen_mode < 0) || (screen_mode > IMG_TUNE_COUNT)) {
		pr_err("%s: invalid input data(%d). Retry(0-5).\n", __func__, screen_mode);
		return -EINVAL;
	}
	
	if (screen_mode == IMG_TUNE_COUNT) {
		pr_info("%s: send the screen mode on(%d) from kernel.\n", __func__, img_tune_mode);
	} else {
		img_tune_mode = screen_mode;
		pr_info("%s: send the screen mode on(%d) from user.\n", __func__, img_tune_mode);
	}

	if(img_tune_cmds_set->img_tune_cmds[img_tune_mode].cmd_cnt) {
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
//		0 : CM0 / 1 : CM0 + PLC 60% / 2 : CM1 / 3 : CM1 + PLC 60% / 4 : CM2 / 5 : CM2 + PLC 60%
		mdss_dsi_panel_cmds_send(ctrl, &img_tune_cmds_set->img_tune_cmds[img_tune_mode]);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	}
	return 0;
}
예제 #14
0
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable)
{
	uint32_t panic_robust_ctrl;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();

	if (!mdata->has_panic_ctrl)
		goto end;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	panic_robust_ctrl = readl_relaxed(mdata->mdp_base +
			MMSS_MDP_PANIC_ROBUST_CTRL);
	if (enable)
		panic_robust_ctrl |= BIT(pipe->panic_ctrl_ndx);
	else
		panic_robust_ctrl &= ~BIT(pipe->panic_ctrl_ndx);
	writel_relaxed(panic_robust_ctrl,
				mdata->mdp_base + MMSS_MDP_PANIC_ROBUST_CTRL);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

end:
	return 0;
}
/**
 * @mdss_mdp_cdm_setup - Sets up the CDM block based on the usecase. The CDM
 *			 block should be initialized before calling this
 *			 function.
 * @cdm:	         Pointer to the CDM structure.
 * @data:                Pointer to the structure containing configuration
 *			 data.
 */
int mdss_mdp_cdm_setup(struct mdss_mdp_cdm *cdm, struct mdp_cdm_cfg *data)
{
	int rc = 0;

	if (!cdm || !data) {
		pr_err("%s: invalid arguments\n", __func__);
		return -EINVAL;
	}

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mutex_lock(&cdm->lock);
	/* Setup CSC block */
	rc = mdss_mdp_cdm_csc_setup(cdm, data);
	if (rc) {
		pr_err("%s: csc configuration failure\n", __func__);
		goto fail;
	}

	/* Setup chroma down sampler */
	rc = mdss_mdp_cdm_cdwn_setup(cdm, data);
	if (rc) {
		pr_err("%s: cdwn configuration failure\n", __func__);
		goto fail;
	}

	/* Setup HDMI packer */
	rc = mdss_mdp_cdm_out_packer_setup(cdm, data);
	if (rc) {
		pr_err("%s: out packer configuration failure\n", __func__);
		goto fail;
	}

	memcpy(&cdm->setup, data, sizeof(struct mdp_cdm_cfg));

fail:
	mutex_unlock(&cdm->lock);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
	return rc;
}
예제 #16
0
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable)
{
	uint32_t panic_robust_ctrl;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();

	if (!mdata->has_panic_ctrl)
		goto end;

	switch (mdss_mdp_panic_signal_support_mode(mdata, pipe)) {
	case MDSS_MDP_PANIC_COMMON_REG_CFG:
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
		panic_robust_ctrl = readl_relaxed(mdata->mdp_base +
				MMSS_MDP_PANIC_ROBUST_CTRL);
		if (enable)
			panic_robust_ctrl |= BIT(pipe->panic_ctrl_ndx);
		else
			panic_robust_ctrl &= ~BIT(pipe->panic_ctrl_ndx);
		writel_relaxed(panic_robust_ctrl,
				mdata->mdp_base + MMSS_MDP_PANIC_ROBUST_CTRL);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
		break;
	case MDSS_MDP_PANIC_PER_PIPE_CFG:
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
		panic_robust_ctrl = mdss_mdp_pipe_read(pipe,
				MDSS_MDP_REG_SSPP_QOS_CTRL);
		if (enable)
			panic_robust_ctrl |= BIT(0);
		else
			panic_robust_ctrl &= ~BIT(0);
		mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL,
					panic_robust_ctrl);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
		break;
	}

end:
	return 0;
}
예제 #17
0
void htc_set_pp_pa(struct mdss_mdp_ctl *ctl)
{
	struct mdss_data_type *mdata;
	struct mdss_mdp_mixer *mixer;
	u32 base = 0, opmode;
	char __iomem *basel;

	
	if (htc_mdss_pp_pa[HUE_INDEX].req_value == htc_mdss_pp_pa[HUE_INDEX].cur_value)
		return;

	if (htc_mdss_pp_pa[HUE_INDEX].req_value >= HUE_MAX)
		return;

	mdata = mdss_mdp_get_mdata();
	mixer = mdata->mixer_intf;

	base = MDSS_MDP_REG_DSPP_OFFSET(0);
	basel = mixer->dspp_base;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);

	MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_PA_BASE, htc_mdss_pp_pa[HUE_INDEX].req_value);

	opmode = MDSS_MDP_REG_READ(base);
	opmode |= (1 << 20); 
	writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE);

	ctl->flush_bits |= BIT(13);

	wmb();
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	htc_mdss_pp_pa[HUE_INDEX].cur_value = htc_mdss_pp_pa[HUE_INDEX].req_value;
	PR_DISP_INFO("%s pp_hue = 0x%x\n", __func__, htc_mdss_pp_pa[HUE_INDEX].req_value);
}
/**
 * @mdss_mdp_cdm_destroy - Destroys the CDM configuration and return it to
 *			   default state.
 * @cdm:                   Pointer to the CDM structure
 */
int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm)
{
	int rc = 0;

	if (!cdm) {
		pr_err("%s: invalid parameters\n", __func__);
		return -EINVAL;
	}

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mutex_lock(&cdm->lock);
	/* Disable HDMI packer */
	writel_relaxed(0x0, cdm->base + MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE);

	/* Put CDM in bypass */
	writel_relaxed(0x0, cdm->mdata->mdp_base + MDSS_MDP_MDP_OUT_CTL_0);

	mutex_unlock(&cdm->lock);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	kref_put(&cdm->kref, mdss_mdp_cdm_free);

	return rc;
}
int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
{
	struct mdss_panel_data *pdata;
	int ret = 0;

	pdata = ctl->panel_data;

	pdata->panel_info.cont_splash_enabled = 0;

	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
			NULL);

	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	return ret;
}
static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
{
	unsigned long flags;
	mutex_lock(&ctx->clk_mtx);
	if (!ctx->clk_enabled) {
		ctx->clk_enabled = 1;
		mdss_mdp_ctl_intf_event
			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	}
	spin_lock_irqsave(&ctx->clk_lock, flags);
	if (!ctx->rdptr_enabled)
		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
	ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
	spin_unlock_irqrestore(&ctx->clk_lock, flags);
	mutex_unlock(&ctx->clk_mtx);
}
static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
{
	unsigned long flags;
	int set_clk_off = 0;

	mutex_lock(&ctx->clk_mtx);
	spin_lock_irqsave(&ctx->clk_lock, flags);
	if (!ctx->rdptr_enabled)
		set_clk_off = 1;
	spin_unlock_irqrestore(&ctx->clk_lock, flags);

	if (ctx->clk_enabled && set_clk_off) {
		ctx->clk_enabled = 0;
		mdss_mdp_ctl_intf_event
			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	}
	mutex_unlock(&ctx->clk_mtx);
}
static int post_reg_access(struct msm_fb_data_type *mfd)
{
	struct mdss_panel_data *pdata;
	int ret = 0;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;

	pdata = dev_get_platdata(&mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: no panel connected\n", __func__);
		return -ENODEV;
	}

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
				panel_data);

	mdss_dsi_clk_ctrl(ctrl_pdata, 0);
	mdss_bus_bandwidth_ctrl(0);
	mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	return ret;
}
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
{
	struct mdss_mdp_video_ctx *ctx;
	int off;

	pr_debug("stop ctl=%d\n", ctl->num);

	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
	if (!ctx) {
		pr_err("invalid ctx for ctl=%d\n", ctl->num);
		return -ENODEV;
	}

	if (ctx->timegen_en) {
		off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
		ctx->timegen_en = false;
	}

	memset(ctx, 0, sizeof(*ctx));

	return 0;
}
예제 #24
0
/*
 * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically.
 * @work     : dsi controller status data
 * @interval : duration in milliseconds to schedule work queue
 *
 * This function calls check_status API on DSI controller to send the BTA
 * command. If DSI controller fails to acknowledge the BTA command, it sends
 * the PANEL_ALIVE=0 status to HAL layer.
 */
void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval)
{
    struct dsi_status_data *pstatus_data = NULL;
    struct mdss_panel_data *pdata = NULL;
    struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
    struct mdss_overlay_private *mdp5_data = NULL;
    struct mdss_mdp_ctl *ctl = NULL;
    int ret = 0;

    pstatus_data = container_of(to_delayed_work(work),
                                struct dsi_status_data, check_status);
    if (!pstatus_data || !(pstatus_data->mfd)) {
        pr_err("%s: mfd not available\n", __func__);
        return;
    }

    pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev);
    if (!pdata) {
        pr_err("%s: Panel data not available\n", __func__);
        return;
    }

    ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
                              panel_data);
    if (!ctrl_pdata || (!ctrl_pdata->check_status &&
                        (ctrl_pdata->status_mode != ESD_TE))) {
        pr_err("%s: DSI ctrl or status_check callback not available\n",
               __func__);
        return;
    }

    mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd);
    ctl = mfd_to_ctl(pstatus_data->mfd);

    if (!ctl) {
        pr_err("%s: Display is off\n", __func__);
        return;
    }

    if (ctl->power_state == MDSS_PANEL_POWER_OFF) {
        schedule_delayed_work(&pstatus_data->check_status,
                              msecs_to_jiffies(interval));
        pr_debug("%s: ctl not powered on\n", __func__);
        return;
    }

    if (ctrl_pdata->status_mode == ESD_TE) {
        mdss_check_te_status(ctrl_pdata, pstatus_data, interval);
        return;
    }

    mutex_lock(&ctrl_pdata->mutex);
    if (ctl->shared_lock)
        mutex_lock(ctl->shared_lock);
    mutex_lock(&mdp5_data->ov_lock);

    if (pstatus_data->mfd->shutdown_pending) {
        mutex_unlock(&mdp5_data->ov_lock);
        if (ctl->shared_lock)
            mutex_unlock(ctl->shared_lock);
        mutex_unlock(&ctrl_pdata->mutex);
        pr_err("%s: DSI turning off, avoiding panel status check\n",
               __func__);
        return;
    }

    /*
     * For the command mode panels, we return pan display
     * IOCTL on vsync interrupt. So, after vsync interrupt comes
     * and when DMA_P is in progress, if the panel stops responding
     * and if we trigger BTA before DMA_P finishes, then the DSI
     * FIFO will not be cleared since the DSI data bus control
     * doesn't come back to the host after BTA. This may cause the
     * display reset not to be proper. Hence, wait for DMA_P done
     * for command mode panels before triggering BTA.
     */
    if (ctl->wait_pingpong)
        ctl->wait_pingpong(ctl, NULL);

    pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);

    mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
    ret = ctrl_pdata->check_status(ctrl_pdata);
    mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

    mutex_unlock(&mdp5_data->ov_lock);
    if (ctl->shared_lock)
        mutex_unlock(ctl->shared_lock);
    mutex_unlock(&ctrl_pdata->mutex);

    if ((pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON)) {
        if (ret > 0)
            schedule_delayed_work(&pstatus_data->check_status,
                                  msecs_to_jiffies(interval));
        else
            mdss_report_panel_dead(pstatus_data);
    }
}
/*
 * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically.
 * @work     : dsi controller status data
 * @interval : duration in milliseconds to schedule work queue
 *
 * This function calls check_status API on DSI controller to send the BTA
 * command. If DSI controller fails to acknowledge the BTA command, it sends
 * the PANEL_ALIVE=0 status to HAL layer.
 */
void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval)
{
	struct dsi_status_data *pstatus_data = NULL;
	struct mdss_panel_data *pdata = NULL;
	struct mipi_panel_info *mipi = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdss_overlay_private *mdp5_data = NULL;
	struct mdss_mdp_ctl *ctl = NULL;
	int ret = 0;
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2015/01/09  Add for 14045 TP and LCD ESD */
	int tp_ret=-1;
#endif /*VENDOR_EDIT*/

	pstatus_data = container_of(to_delayed_work(work),
		struct dsi_status_data, check_status);
	if (!pstatus_data || !(pstatus_data->mfd)) {
		pr_err("%s: mfd not available\n", __func__);
		return;
	}

	pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: Panel data not available\n", __func__);
		return;
	}
	mipi = &pdata->panel_info.mipi;

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
							panel_data);
	if (!ctrl_pdata || !ctrl_pdata->check_status) {
		pr_err("%s: DSI ctrl or status_check callback not available\n",
								__func__);
		return;
	}

	mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd);
	ctl = mfd_to_ctl(pstatus_data->mfd);

	if (!ctl) {
		pr_err("%s: Display is off\n", __func__);
		return;
	}

	if (!ctl->power_on) {
		schedule_delayed_work(&pstatus_data->check_status,
			msecs_to_jiffies(interval));
		pr_err("%s: ctl not powered on\n", __func__);
		return;
	}

	/*
	 * TODO: Because mdss_dsi_cmd_mdp_busy has made sure DMA to
	 * be idle in mdss_dsi_cmdlist_commit, it is not necessary
	 * to acquire ov_lock in case of video mode. Removing this
	 * lock to fix issues so that ESD thread could block other
	 * overlay operations. Need refine this lock for command mode
	 */
	if (mipi->mode == DSI_CMD_MODE)
		mutex_lock(&mdp5_data->ov_lock);

	if (pstatus_data->mfd->shutdown_pending ||
		!pstatus_data->mfd->panel_power_on) {
		if (mipi->mode == DSI_CMD_MODE)
			mutex_unlock(&mdp5_data->ov_lock);
		pr_err("%s: DSI turning off, avoiding panel status check\n",
							__func__);
		return;
	}

	/*
	 * For the command mode panels, we return pan display
	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
	 * and when DMA_P is in progress, if the panel stops responding
	 * and if we trigger BTA before DMA_P finishes, then the DSI
	 * FIFO will not be cleared since the DSI data bus control
	 * doesn't come back to the host after BTA. This may cause the
	 * display reset not to be proper. Hence, wait for DMA_P done
	 * for command mode panels before triggering BTA.
	 */
	if (ctl->wait_pingpong)
		ctl->wait_pingpong(ctl, NULL);

	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	ret = ctrl_pdata->check_status(ctrl_pdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	if (mipi->mode == DSI_CMD_MODE)
		mutex_unlock(&mdp5_data->ov_lock);
	
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2015/01/09  Add for 14045 TP and LCD ESD  */
	if(is_project(OPPO_14045) && tp_esd_check_fn!=NULL)
	{
		tp_ret = tp_esd_check_fn();
	}else{
		tp_ret = 1;
	}
#endif /*VENDOR_EDIT*/
	
	if ((pstatus_data->mfd->panel_power_on)) {
		/* VENDOR_EDIT Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2015/01/09  Modified  for 14045 TP and LCD ESD  */
		//if (ret > 0) {
		if ((ret > 0) && (tp_ret >= 0)) {
		/*VENDOR_EDIT Modified end*/
			schedule_delayed_work(&pstatus_data->check_status,
				msecs_to_jiffies(interval));
		} else {
			char *envp[2] = {"PANEL_ALIVE=0", NULL};
			pdata->panel_info.panel_dead = true;
			ret = kobject_uevent_env(
				&pstatus_data->mfd->fbi->dev->kobj,
							KOBJ_CHANGE, envp);
			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
							__func__, envp[0]);
		}
	}
}
예제 #26
0
void klog(void)
{
	int i;
	static u32 *buff = NULL;
	int mdp_reg_count = 0;
	struct mdss_panel_data *pdata = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	int mdp_reg_dump_en;
	unsigned long flags;
	
	/* NULL Checks */
	if(mdata == NULL) return;
	if(mdata->ctl_off == NULL) return;
	pdata = (mdata->ctl_off+0)->panel_data;
	if(pdata ==NULL) return;
	
	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
				panel_data);
	mdp_reg_dump_en = (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT);
	if(debug_mdp->reg_log.last*4 >= debug_mdp->reg_log.len  ) return;
	if(debug_mdp->reg_log.len == 0) return;

	
	pr_debug("KK: -----------> Inside %s",__func__);

	
#ifdef __KERNEL__
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	spin_lock_irqsave(&xlock, flags);
	
#else
	if((readl_relaxed(HWIO_MMSS_MDSS_AHB_CBCR_ADDR) & 0x80000000) != 0x0) {
		pr_info("AHB Clock not ON, Cannot Read MDP Regs\n");
	}
	//Switch on clcok
#endif
	if(debug_mdp && buff == NULL){
		buff = (u32 *)((char *)debug_mdp + (sizeof(struct debug_mdp) + debug_mdp->reg_log.offset));
	}
	else if(!debug_mdp){
		pr_info("Debug module not Initialized\n");
		return ;
	}
	
	pr_debug("KK:------------------->(%s)::>> first: %x \t last: %x buff:%p-%p\n", __func__, debug_mdp->reg_log.first, debug_mdp->reg_log.last,buff,buff+debug_mdp->reg_log.len);

if(!mdp_reg_dump_en)
	i = sizeof(mdss_reg_desc)/sizeof(struct reg_desc) -1;
else
	i = 1;
	for(; i < sizeof(mdss_reg_desc)/sizeof(struct reg_desc) ; i++){
		buff[debug_mdp->reg_log.last++] = START_MAGIC;
        	buff[debug_mdp->reg_log.last++] = mdss_reg_desc[i].base;
#if defined(__KERNEL__)
		if(fill_reg_log(buff, mdss_reg_desc[i].vaddr, mdss_reg_desc[i].len))
			pr_info("failed to dump lcd regs at %x ----------> KK\n",mdss_reg_desc[i].base);
#else
		if(fill_reg_log(buff, base, len*4))
			pr_info("failed to dump lcd regs at %x ----------> KK\n",base);
#endif	
	}
#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226)	
if(mdp_reg_dump_en){
	
	buff[debug_mdp->reg_log.last++] = START_MAGIC;
        buff[debug_mdp->reg_log.last++] = mdss_reg_desc[0].base;

	for(i = 0; i < sizeof(mdp_reg_info)/sizeof(u32); i++){
		int len;
		u32 base;
		len = mdp_reg_info[i] & 0xfff00000;
		len = len >> 20;
		len += 1;
		mdp_reg_count += len;
		base = mdp_reg_info[i] & 0x000fffff;
		base = base | mdss_reg_desc[0].base;
#if defined(__KERNEL__)
		if(fill_reg_log(buff, mdp_reg_vaddr[i], len*4))
			pr_info("failed to dump lcd regs at %x ----------> KK\n",base);

#else
			if(fill_reg_log(buff, base, len*4))
			pr_info("failed to dump lcd regs at %x ----------> KK\n",base);
#endif
	}
}
#endif
#ifdef __KERNEL__
	
	spin_unlock_irqrestore(&xlock, flags);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

#else
        //Switch off clock 
#endif
	pr_debug("total mdp regs: %d\n",mdp_reg_count);
}
예제 #27
0
static void check_dsi_ctrl_status(struct work_struct *work)
{
	struct dsi_status_data *pdsi_status = NULL;
	struct mdss_panel_data *pdata = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdss_overlay_private *mdp5_data = NULL;
	struct mdss_mdp_ctl *ctl = NULL;
	int ret = 0;

	pdsi_status = container_of(to_delayed_work(work),
		struct dsi_status_data, check_status);
	if (!pdsi_status) {
		pr_err("%s: DSI status data not available\n", __func__);
		return;
	}

  //patch + case1481899 mayu 3.27
	if(!pdsi_status->mfd){
	  pr_err("%s:mfd is NULL \n",__func__);
	  return;
	}
  //patch - case1481899 mayu 3.27

	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: Panel data not available\n", __func__);
		return;
	}

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
							panel_data);
	if (!ctrl_pdata || !ctrl_pdata->check_status) {
		pr_err("%s: DSI ctrl or status_check callback not available\n",
								__func__);
		return;
	}

//+++duguowei,crash if no lcd
	if(!ctrl_pdata->panel_name)
		return;
//---duguowei,crash if no lcd
	mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd);
	ctl = mfd_to_ctl(pdsi_status->mfd);

	if (ctl->shared_lock)
		mutex_lock(ctl->shared_lock);
	mutex_lock(&mdp5_data->ov_lock);

	/*
	 * For the command mode panels, we return pan display
	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
	 * and when DMA_P is in progress, if the panel stops responding
	 * and if we trigger BTA before DMA_P finishes, then the DSI
	 * FIFO will not be cleared since the DSI data bus control
	 * doesn't come back to the host after BTA. This may cause the
	 * display reset not to be proper. Hence, wait for DMA_P done
	 * for command mode panels before triggering BTA.
	 */
	if (pdsi_status->mfd->shutdown_pending) {
		mutex_unlock(&mdp5_data->ov_lock);
		if (ctl->shared_lock)
			mutex_unlock(ctl->shared_lock);
		return;
	}
	
	if (ctl->wait_pingpong)
		ctl->wait_pingpong(ctl, NULL);

	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	ret = ctrl_pdata->check_status(ctrl_pdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	mutex_unlock(&mdp5_data->ov_lock);
	if (ctl->shared_lock)
		mutex_unlock(ctl->shared_lock);

	if ((pdsi_status->mfd->panel_power_on)) {
		if (ret > 0) {
			schedule_delayed_work(&pdsi_status->check_status,
				msecs_to_jiffies(pdsi_status->check_interval));
		} else {
#ifdef CONFIG_ZTEMT_NE501_LCD
			if (mipi_lcd_esd_command(ctrl_pdata)) {
				char *envp[2] = {"PANEL_ALIVE=0", NULL};
				pdata->panel_info.panel_dead = true;
				ret = kobject_uevent_env(
					&pdsi_status->mfd->fbi->dev->kobj,
								KOBJ_CHANGE, envp);
				pr_err("%s: Panel has gone bad, sending uevent - %s\n",
								__func__, envp[0]);
				printk("default reset panel\n");
			}
#else
			char *envp[2] = {"PANEL_ALIVE=0", NULL};
			pdata->panel_info.panel_dead = true;
			ret = kobject_uevent_env(
				&pdsi_status->mfd->fbi->dev->kobj,
							KOBJ_CHANGE, envp);
			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
							__func__, envp[0]);
#endif
		}
	}
}
/*
 * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically.
 * @work     : dsi controller status data
 * @interval : duration in milliseconds to schedule work queue
 *
 * This function calls check_status API on DSI controller to send the BTA
 * command. If DSI controller fails to acknowledge the BTA command, it sends
 * the PANEL_ALIVE=0 status to HAL layer.
 */
void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval)
{
	struct dsi_status_data *pstatus_data = NULL;
	struct mdss_panel_data *pdata = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdss_overlay_private *mdp5_data = NULL;
	struct mdss_mdp_ctl *ctl = NULL;
	int ret = 0;

	pstatus_data = container_of(to_delayed_work(work),
		struct dsi_status_data, check_status);
	if (!pstatus_data || !(pstatus_data->mfd)) {
		pr_err("%s: mfd not available\n", __func__);
		return;
	}

	pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: Panel data not available\n", __func__);
		return;
	}

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
							panel_data);
	if (!ctrl_pdata || !ctrl_pdata->check_status) {
		pr_err("%s: DSI ctrl or status_check callback not available\n",
								__func__);
		return;
	}

	mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd);
	ctl = mfd_to_ctl(pstatus_data->mfd);

	if (!ctl) {
		pr_err("%s: Display is off\n", __func__);
		return;
	}

	if (!ctl->power_on) {
		schedule_delayed_work(&pstatus_data->check_status,
			msecs_to_jiffies(interval));
		pr_err("%s: ctl not powered on\n", __func__);
		return;
	}

	if (ctl->shared_lock)
		mutex_lock(ctl->shared_lock);
	mutex_lock(&mdp5_data->ov_lock);

	if (pstatus_data->mfd->shutdown_pending ||
		!pstatus_data->mfd->panel_power_on) {
		mutex_unlock(&mdp5_data->ov_lock);
		if (ctl->shared_lock)
			mutex_unlock(ctl->shared_lock);
		pr_err("%s: DSI turning off, avoiding panel status check\n",
							__func__);
		return;
	}

	/*
	 * For the command mode panels, we return pan display
	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
	 * and when DMA_P is in progress, if the panel stops responding
	 * and if we trigger BTA before DMA_P finishes, then the DSI
	 * FIFO will not be cleared since the DSI data bus control
	 * doesn't come back to the host after BTA. This may cause the
	 * display reset not to be proper. Hence, wait for DMA_P done
	 * for command mode panels before triggering BTA.
	 */
	if (ctl->wait_pingpong)
		ctl->wait_pingpong(ctl, NULL);

	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	ret = ctrl_pdata->check_status(ctrl_pdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	mutex_unlock(&mdp5_data->ov_lock);
	if (ctl->shared_lock)
		mutex_unlock(ctl->shared_lock);

	if ((pstatus_data->mfd->panel_power_on)) {
		if (ret > 0) {
			schedule_delayed_work(&pstatus_data->check_status,
				msecs_to_jiffies(interval));
		} else {
			char *envp[2] = {"PANEL_ALIVE=0", NULL};
			pdata->panel_info.panel_dead = true;
			ret = kobject_uevent_env(
				&pstatus_data->mfd->fbi->dev->kobj,
							KOBJ_CHANGE, envp);
			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
							__func__, envp[0]);
		}
	}
}
void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval)
{
	struct dsi_status_data *pstatus_data = NULL;
	struct mdss_panel_data *pdata = NULL;
	struct mipi_panel_info *mipi = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdss_overlay_private *mdp5_data = NULL;
	struct mdss_mdp_ctl *ctl = NULL;
	int ret = 0;

	pstatus_data = container_of(to_delayed_work(work),
		struct dsi_status_data, check_status);
	if (!pstatus_data || !(pstatus_data->mfd)) {
		pr_err("%s: mfd not available\n", __func__);
		return;
	}

	pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: Panel data not available\n", __func__);
		return;
	}
	mipi = &pdata->panel_info.mipi;

	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
							panel_data);
	if (!ctrl_pdata || (!ctrl_pdata->check_status &&
		(ctrl_pdata->status_mode != ESD_TE))) {
		pr_err("%s: DSI ctrl or status_check callback not available\n",
								__func__);
		return;
	}

	mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd);
	ctl = mfd_to_ctl(pstatus_data->mfd);

	if (!ctl) {
		pr_err("%s: Display is off\n", __func__);
		return;
	}

	if (ctl->power_state == MDSS_PANEL_POWER_OFF) {
		schedule_delayed_work(&pstatus_data->check_status,
			msecs_to_jiffies(interval));
		pr_debug("%s: ctl not powered on\n", __func__);
		return;
	}

	if (ctrl_pdata->status_mode == ESD_TE) {
		mdss_check_te_status(ctrl_pdata, pstatus_data, interval);
		return;
	}



	mutex_lock(&ctl->offlock);
	if (mipi->mode == DSI_CMD_MODE)
		mutex_lock(&mdp5_data->ov_lock);

		if (mdss_panel_is_power_off(pstatus_data->mfd->panel_power_state) ||
			pstatus_data->mfd->shutdown_pending) {
		if (mipi->mode == DSI_CMD_MODE)
			mutex_unlock(&mdp5_data->ov_lock);
		mutex_unlock(&ctl->offlock);
		pr_err("%s: DSI turning off, avoiding panel status check\n",
							__func__);
		return;
	}

	if (ctl->wait_pingpong)
		ctl->wait_pingpong(ctl, NULL);

	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	ret = ctrl_pdata->check_status(ctrl_pdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	if (mipi->mode == DSI_CMD_MODE)
		mutex_unlock(&mdp5_data->ov_lock);
	mutex_unlock(&ctl->offlock);

	if ((pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON)) {
		if (ret > 0)
			schedule_delayed_work(&pstatus_data->check_status,
				msecs_to_jiffies(interval));
		else
			mdss_report_panel_dead(pstatus_data);
	}
}
예제 #30
0
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
	int mixer1_changed, mixer2_changed;
	int ret = 0;
	int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
	u32 update_flags = 0;

	if (!ctl) {
		pr_err("display function not set\n");
		return -ENODEV;
	}

	pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);

	ret = mutex_lock_interruptible(&ctl->lock);
	if (ret)
		return ret;

	if (!ctl->power_on) {
		mutex_unlock(&ctl->lock);
		return 0;
	}

	mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	if (mixer1_changed || mixer2_changed) {
		perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);

		if (ctl->prepare_fnc)
			ret = ctl->prepare_fnc(ctl, arg);
		if (ret) {
			pr_err("error preparing display\n");
			goto done;
		}

		if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
			mdss_mdp_ctl_perf_commit(update_flags);

		if (mixer1_changed)
			mdss_mdp_mixer_update(ctl->mixer_left);
		if (mixer2_changed)
			mdss_mdp_mixer_update(ctl->mixer_right);

		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode);
		ctl->flush_bits |= BIT(17);	/* CTL */
	}

	/* postprocessing setup, including dspp */
	mdss_mdp_pp_setup(ctl);
	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
	wmb();
	ctl->flush_bits = 0;

	if (ctl->display_fnc)
		ret = ctl->display_fnc(ctl, arg); /* kickoff */
	if (ret)
		pr_warn("error displaying frame\n");

	ctl->play_cnt++;

	if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
		mdss_mdp_ctl_perf_commit(update_flags);

done:
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);

	mutex_unlock(&ctl->lock);

	return ret;
}