Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d96e425 authored by Ingrid Gallardo's avatar Ingrid Gallardo Committed by Ujwal Patel
Browse files

msm: mdss: fix timing gen flush sequence for dynamic fps



Timing generator update cannot happen in the
same frame boundary/vsync cycle where a change
in the mixer configuration is requested.
Enforce this sequence by moving timing generator
programming to the commit thread, so driver can
wait for one vsync cycle when timing generator
has been modified due a dynamic fps update.

Change-Id: Ifac5332f3de45479ebc0a6ab0c1f7cf7b48a41b0
Signed-off-by: default avatarIngrid Gallardo <ingridg@codeaurora.org>
parent 13473754
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -234,8 +234,7 @@ struct mdss_mdp_ctl_intfs_ops {
					struct mdss_mdp_vsync_handler *);
	int (*remove_vsync_handler)(struct mdss_mdp_ctl *,
					struct mdss_mdp_vsync_handler *);
	int (*config_fps_fnc)(struct mdss_mdp_ctl *ctl,
				struct mdss_mdp_ctl *sctl, int new_fps);
	int (*config_fps_fnc)(struct mdss_mdp_ctl *ctl, int new_fps);
	int (*restore_fnc)(struct mdss_mdp_ctl *ctl, bool locked);
	int (*early_wake_up_fnc)(struct mdss_mdp_ctl *ctl);

@@ -1280,7 +1279,7 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval);
int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
						u32 *copyback);
int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps);
int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe);
int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
+30 −5
Original line number Diff line number Diff line
@@ -4136,15 +4136,40 @@ int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe,
	return 0;
}

int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps)
int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl)
{
	struct mdss_panel_info *pinfo;
	struct mdss_overlay_private *mdp5_data;
	int ret = 0;
	struct mdss_mdp_ctl *sctl = NULL;
	int new_fps;

	sctl = mdss_mdp_get_split_ctl(ctl);
	if (!ctl->panel_data || !ctl->mfd)
		return -ENODEV;

	pinfo = &ctl->panel_data->panel_info;

	if (!pinfo->dynamic_fps || !ctl->ops.config_fps_fnc)
		return 0;

	if (ctl->ops.config_fps_fnc)
		ret = ctl->ops.config_fps_fnc(ctl, sctl, fps);
	mdp5_data = mfd_to_mdp5_data(ctl->mfd);
	if (!mdp5_data)
		return -ENODEV;

	mutex_lock(&mdp5_data->dfps_lock);
	new_fps = pinfo->new_fps;
	mutex_unlock(&mdp5_data->dfps_lock);

	if (new_fps == pinfo->mipi.frame_rate) {
		pr_debug("FPS is already %d\n", new_fps);
		return 0;
	}

	ret = ctl->ops.config_fps_fnc(ctl, new_fps);
	if (!ret)
		pr_debug("fps set to %d\n", new_fps);
	else
		pr_err("Failed to configure %d fps rc=%d\n",
			new_fps, ret);

	return ret;
}
+61 −31
Original line number Diff line number Diff line
@@ -828,19 +828,32 @@ static int mdss_mdp_video_dfps_wait4vsync(struct mdss_mdp_ctl *ctl)
	struct mdss_mdp_video_ctx *ctx;

	ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx) {
		pr_err("invalid ctx\n");
		return -ENODEV;
	}

	video_vsync_irq_enable(ctl, true);
	reinit_completion(&ctx->vsync_comp);
	rc = wait_for_completion_timeout(&ctx->vsync_comp,
		usecs_to_jiffies(VSYNC_TIMEOUT_US));
	WARN(rc <= 0, "timeout (%d) vsync interrupt on ctl=%d\n",
		rc, ctl->num);

	if (rc <= 0) {
		pr_warn("vsync timeout %d fallback to poll mode\n",
			ctl->num);
		rc = mdss_mdp_video_pollwait(ctl);
		if (rc) {
			pr_err("error polling for vsync\n");
			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
				"dsi1_ctrl", "dsi1_phy", "vbif", "dbg_bus",
				"vbif_dbg_bus", "panic");
		}
	} else {
		rc = 0;
	}
	video_vsync_irq_disable(ctl);
	if (rc <= 0)
		return -EPERM;

	return 0;
	return rc;
}

static int mdss_mdp_video_dfps_check_line_cnt(struct mdss_mdp_ctl *ctl)
@@ -881,14 +894,29 @@ static void mdss_mdp_video_timegen_flush(struct mdss_mdp_ctl *ctl,
	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush);
}

static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
					struct mdss_mdp_ctl *sctl, int new_fps)
/**
 * mdss_mdp_video_config_fps() - modify the fps.
 * @ctl: pointer to the master controller.
 * @new_fps: new fps to be set.
 *
 * This function configures the hardware to modify the fps.
 * Note that this function will flush the DSI and MDP
 * to reconfigure the fps in VFP and HFP methods.
 * Given above statement, is callers responsibility to call
 * this function at the beginning of the frame, so it can be
 * guaranteed that flush of both (DSI and MDP) happen within
 * the same frame.
 *
 * Return: 0 - succeed, otherwise - fail
 */
static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
{
	struct mdss_mdp_video_ctx *ctx, *sctx = NULL;
	struct mdss_panel_data *pdata;
	int rc = 0;
	u32 hsync_period, vsync_period;
	struct mdss_data_type *mdata;
	struct mdss_data_type *mdata = ctl->mdata;
	struct mdss_mdp_ctl *sctl = NULL;

	ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
	if (!ctx || !ctx->timegen_en || !ctx->ref_cnt) {
@@ -896,7 +924,7 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
		return -EINVAL;
	}

	mdata = ctl->mdata;
	sctl = mdss_mdp_get_split_ctl(ctl);
	if (sctl) {
		sctx = (struct mdss_mdp_video_ctx *) sctl->intf_ctx[MASTER_CTX];
		if (!sctx) {
@@ -919,16 +947,12 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
		goto end;
	}

	if (!pdata->panel_info.dynamic_fps) {
		pr_err("%s: Dynamic fps not enabled for this panel\n",
						__func__);
		rc = -EINVAL;
		goto end;
	}

	vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
	hsync_period = mdss_panel_get_htotal(&pdata->panel_info, true);

	pr_debug("ctl:%d dfps_update:%d fps:%d\n",
		ctl->num, pdata->panel_info.dfps_update, new_fps);

	if (pdata->panel_info.dfps_update
			!= DFPS_SUSPEND_RESUME_MODE) {
		if (pdata->panel_info.dfps_update
@@ -942,6 +966,7 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
					MDSS_EVENT_PANEL_UPDATE_FPS,
					(void *) (unsigned long) new_fps,
					CTL_INTF_EVENT_FLAG_DEFAULT);

			WARN(rc, "intf %d panel fps update error (%d)\n",
							ctl->intf_num, rc);
		} else if (pdata->panel_info.dfps_update
@@ -955,19 +980,6 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
				goto end;
			}

			/*
			 * there is possibility that the time of mdp flush
			 * bit set and the time of dsi flush bit are cross
			 * vsync boundary. therefore wait4vsync is needed
			 * to guarantee both flush bits are set within same
			 * vsync period regardless of mdp revision.
			 */
			rc = mdss_mdp_video_dfps_wait4vsync(ctl);
			if (rc < 0) {
				pr_err("Error during wait4vsync\n");
				goto end;
			}

			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
			spin_lock_irqsave(&ctx->dfps_lock, flags);

@@ -979,14 +991,16 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,

			rc = mdss_mdp_video_fps_update(ctx, pdata, new_fps);
			if (rc < 0) {
				pr_err("%s: Error during DFPS\n", __func__);
				pr_err("%s: Error during DFPS: %d\n", __func__,
					new_fps);
				goto exit_dfps;
			}
			if (sctx) {
				rc = mdss_mdp_video_fps_update(sctx,
							pdata->next, new_fps);
				if (rc < 0) {
					pr_err("%s: DFPS error\n", __func__);
					pr_err("%s: DFPS error fps:%d\n",
						__func__, new_fps);
					goto exit_dfps;
				}
			}
@@ -997,6 +1011,7 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
			WARN(rc, "intf %d panel fps update error (%d)\n",
							ctl->intf_num, rc);

			rc = 0;
			mdss_mdp_fetch_start_config(ctx, ctl);
			if (sctx)
				mdss_mdp_fetch_start_config(sctx, ctl);
@@ -1018,6 +1033,21 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
exit_dfps:
			spin_unlock_irqrestore(&ctx->dfps_lock, flags);
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

			/*
			 * Wait for one vsync to make sure these changes
			 * are applied as part of one single frame and
			 * no mixer changes happen at the same time.
			 * A potential optimization would be not to wait
			 * here, but next mixer programming would need
			 * to wait before programming the flush bits.
			 */
			if (!rc) {
				rc = mdss_mdp_video_dfps_wait4vsync(ctl);
				if (rc < 0)
					pr_err("Error in dfps_wait: %d\n", rc);
			}

		} else {
			pr_err("intf %d panel, unknown FPS mode\n",
							ctl->intf_num);
+28 −14
Original line number Diff line number Diff line
@@ -1991,8 +1991,24 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
	ATRACE_BEGIN("display_wait4comp");
	ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
	ATRACE_END("display_wait4comp");
	mutex_lock(&mdp5_data->ov_lock);

	/*
	 * Configure Timing Engine, if new fps was set.
	 * We need to do this after the wait for vsync
	 * to guarantee that mdp flush bit and dsi flush
	 * bit are set within the same vsync period
	 * regardless of  mdp revision.
	 */
	ATRACE_BEGIN("fps_update");
	ret = mdss_mdp_ctl_update_fps(ctl);
	ATRACE_END("fps_update");

	if (IS_ERR_VALUE(ret)) {
		pr_err("failed to update fps!\n");
		goto commit_fail;
	}

	mutex_lock(&mdp5_data->ov_lock);
	/*
	 * If there is no secure display session and sd_enabled, disable the
	 * secure display session
@@ -2651,8 +2667,10 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
		return rc;
	}

	if (!mdp5_data->ctl || !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))
		return 0;
	if (!mdp5_data->ctl || !mdss_mdp_ctl_is_power_on(mdp5_data->ctl)) {
		pr_debug("panel is off\n");
		return count;
	}

	pdata = dev_get_platdata(&mfd->pdev->dev);
	if (!pdata) {
@@ -2660,6 +2678,12 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
		return -ENODEV;
	}

	if (!pdata->panel_info.dynamic_fps) {
		pr_err_once("%s: Dynamic fps not enabled for this panel\n",
				__func__);
		return -EINVAL;
	}

	if (dfps == pdata->panel_info.mipi.frame_rate) {
		pr_debug("%s: FPS is already %d\n",
			__func__, dfps);
@@ -2676,18 +2700,8 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
		pr_warn("Unsupported FPS. Configuring to max_fps = %d\n",
				pdata->panel_info.max_fps);
		dfps = pdata->panel_info.max_fps;
		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
	} else {
		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
	}
	if (!rc) {
		pr_debug("%s: configured to '%d' FPS\n", __func__, dfps);
	} else {
		pr_err("Failed to configure '%d' FPS. rc = %d\n",
							dfps, rc);
		mutex_unlock(&mdp5_data->dfps_lock);
		return rc;
	}

	pdata->panel_info.new_fps = dfps;
	mutex_unlock(&mdp5_data->dfps_lock);
	return count;